{"id":17129732,"url":"https://github.com/lm2343635/shapeview","last_synced_at":"2025-06-11T14:12:58.990Z","repository":{"id":62455288,"uuid":"159451549","full_name":"lm2343635/ShapeView","owner":"lm2343635","description":"A customized shape view with shadow and transparent background supported.","archived":false,"fork":false,"pushed_at":"2023-08-25T12:55:30.000Z","size":756,"stargazers_count":99,"open_issues_count":2,"forks_count":14,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-13T21:43:55.589Z","etag":null,"topics":["customized-shape","cut-layer","ios","ios-lib","mask","shadow","shadowview","shape-layer","swift","transparent-view","uiview"],"latest_commit_sha":null,"homepage":"https://cocoapods.org/pods/ShapeView","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lm2343635.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-28T06:00:23.000Z","updated_at":"2025-01-08T10:22:49.000Z","dependencies_parsed_at":"2024-06-19T06:18:22.154Z","dependency_job_id":"86909238-1279-4b0f-b9e3-a00c5d5ceefc","html_url":"https://github.com/lm2343635/ShapeView","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lm2343635%2FShapeView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lm2343635%2FShapeView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lm2343635%2FShapeView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lm2343635%2FShapeView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lm2343635","download_url":"https://codeload.github.com/lm2343635/ShapeView/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lm2343635%2FShapeView/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259280319,"owners_count":22833424,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["customized-shape","cut-layer","ios","ios-lib","mask","shadow","shadowview","shape-layer","swift","transparent-view","uiview"],"created_at":"2024-10-14T19:10:30.288Z","updated_at":"2025-06-11T14:12:58.940Z","avatar_url":"https://github.com/lm2343635.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ShapeView [![Build Status](https://travis-ci.org/lm2343635/ShapeView.svg?branch=master)](https://travis-ci.org/lm2343635/ShapeView) [![Version](https://img.shields.io/cocoapods/v/ShapeView.svg?style=flat)](https://cocoapods.org/pods/ShapeView) [![License](https://img.shields.io/cocoapods/l/ShapeView.svg?style=flat)](https://cocoapods.org/pods/ShapeView) [![Platform](https://img.shields.io/cocoapods/p/ShapeView.svg?style=flat)](https://cocoapods.org/pods/ShapeView)\n\nShapeView support to create a view with the customized shape, shadow and transparent background at the same time.\n\n## Installation\n\nShapeView is available through [CocoaPods](https://cocoapods.org). \nTo install it, simply add the following line to your Podfile:\n\n```ruby\npod 'ShapeView'\n```\n\n### Using ShapeView\n\nShapeView supports the following attributes.\n\n- `path: ShapePath?`\n- `outerShadow: ShapeShadow`\n- `innerShadow: ShapeShadow`\n- `effect: UIVisualEffect?`\n- `effectAlpha: CGFloat`\n- `backgroundColor: UIColor?`\n\nTo create a customized shape, use `.custom` to draw the shape as the following.\n\n```Swift\nview.path = .custom { [unowned view] in\n    let labelHeight = view.frame.height - Const.height\n    let radius = labelHeight / 2\n\n    $0.move(to: CGPoint(x: radius, y: 0))\n    $0.addArc(\n        withCenter: CGPoint(x: view.frame.width - radius, y: radius), \n        radius: radius, \n        startAngle: -.pi / 2, \n        endAngle: .pi / 2, \n        clockwise: true\n    )\n    $0.addLine(to: CGPoint(x: Const.left + Const.height, y: labelHeight))\n    $0.addLine(to: CGPoint(x: Const.left + Const.height / 2, y: view.frame.height))\n    $0.addLine(to: CGPoint(x: Const.left, y: labelHeight))\n    $0.addArc(\n        withCenter: CGPoint(x: radius, y: radius), \n        radius: radius, \n        startAngle: .pi / 2, \n        endAngle: -.pi / 2, \n        clockwise: true\n    )\n}\n```\n\n### Using prepared shapes\n\nIn the demo app, a dialog view is created with the code above.\n\n![Demo](https://raw.githubusercontent.com/lm2343635/ShapeView/master/screenshoots/demo.png)\n\nThe following shapes are prepared.\n\n```Swift\ncorner(radius: CGFloat, bounds: @escaping GetBounds)\ndialog(radius: CGFloat, arrowPosition: DialogArrowPosition, bounds: @escaping GetBounds)\ncuteDialog(radius: CGFloat, arrowPosition: CuteDialogArrowPosition, bounds: @escaping GetBounds)\nstar(vertex: Int, extrusion: CGFloat = 10, bounds: GetBounds)\n```\n\nHere is a demo to create a dialog view.\n\n```Swift\nview.path = .dialog(radius: 10, arrowPosition: .right(center: 50, width: 40, height: 20)) { [unowned self] in\n    return self.bounds\n}\nview.outerShadow = ShapeShadow(\n    radius: 10,\n    color: .green,\n    opacity: 1,\n    offset: .zero\n)\n```\n\n### Multiple shapes\n\nShapeView supports to add multiple shapes with `.multiple()` as the following.\n\n```swift\nview.path = .multiple(\n    .hollowCorner(radius: 12, outlineWidth: 2) { [unowned view] in\n        view.bounds\n    },\n    .star(vertex: 5, extrusion: 20) { [unowned view] in\n        view.bounds\n    },\n    .custom { [unowned view] in\n        // Add a custom shape here.    \n    }\n)\n```\n\nRun the demp application to find more.\n\n### Using ShapeLayer\n\nWe provide `ShapeLayer` for developers to apply it to your customized view directly.\n\n- `layerPath: ShapePath?` \n- `var outerShadow: ShapeShadow?`\n- `var innerShadow: ShapeShadow?`\n- `effect: UIVisualEffect?`\n- `effectAlpha: CGFloat`\n- `var didUpdateLayer: ((CAShapeLayer) -\u003e Void)?`\n- `var backgroundColor: CGColor?`\n\nWhen the shape layer finish drawing the layer, it calls the `didUpdateLayer` cloure to notify the parent view.\nDevelopers can update the parent view with the first parameter in this closure.\n\n## About the Implementation\n\n**This part introduces how we implement the ShapeView, skip it if you are not interested.** \n\n### Necessity to implement by ourselves\n\nIt is hard to create a customized shape with shadow and transparent background for UIView using the SDK provided by Apple.\nWe have tried to and shadow into the customized shape layer directly with the following code.\n\n```Swift\nlet shapeLayer = CAShapeLayer()\nshapeLayer.path = shapePath.cgPath\nshapeLayer.shadow = UIColor.green.cgColor\nshapeLayer.shadowRadius = 10\nshapeLayer.shadowOffset = .zero\nshapeLayer.shadowOpacity = 1\n\nShapeShadow(\n    radius: 10,\n    color: .green,\n    opacity: 1,\n    offset: .zero\n)\nlayer.masksToBounds = true\n```\n\n- Using a mask\n\n```Swift\nlayer.mask = shapeLayer\n```\n\n![Mask](https://raw.githubusercontent.com/lm2343635/ShapeView/master/screenshoots/error-mask.png)\n\n- Adding a sublayer\n```Swift\nlayer.addSublayer(shapeLayer)\n```\n\n![Sublayer](https://raw.githubusercontent.com/lm2343635/ShapeView/master/screenshoots/error-sublayer.png)\n\nUsing a mask or adding a sublayer cannot implement the effect shown in our demo screenshoot.\n\n### Structure\n\n![Shape layers](https://raw.githubusercontent.com/lm2343635/ShapeView/master/screenshoots/shape-layers.png)\n\nIn the ShapeLayer, we add a shadow layer for the shape and effect, and a container view for storing subviews..\nIf the developer add subview to the ShapeView by the method ```addSubview(_ view:)```, we move it to the container view.\n\n### Creating a hollow mask layer\n\nTo solve the problems, we need to creare a hollow mask layer by ourselves.\nFirstly, we create a shadow layer, and insert it to the ```shapeLayerView```.\n\n```Swift\nlet shadowLayer = CAShapeLayer()\nshadowLayer.path = shapePath.cgPath\nif shadowRadius \u003e 0 \u0026\u0026 shadowColor != .clear {\n    shadowLayer.shadowRadius = shadowRadius\n    shadowLayer.shadowColor = shadowColor.cgColor\n    shadowLayer.shadowOpacity = shadowOpacity\n    shadowLayer.shadowOffset = shaowOffset\n    shadowLayer.fillColor = shadowColor.cgColor\n}\nshadowLayerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }\nshadowLayerView.layer.insertSublayer(shadowLayer, at: 0)\n```\n\n![shapelayer](https://raw.githubusercontent.com/lm2343635/ShapeView/master/screenshoots/shapelayer.png)\n\nThe shadow layer created by ```CAShapeLayer``` is a solid layer.\nWe need to make a cut layer shown as the red area in the following screenshoot, as a mask layer to create a hollow mask layer.\n\n```Swift\nlet cutLayer = CAShapeLayer()\ncutLayer.path = { () -\u003e UIBezierPath in\n    let path = UIBezierPath()\n    path.append(shapePath)\n    path.append(screenPath)\n    path.usesEvenOddFillRule = true\n    return path\n}().cgPath\ncutLayer.fillRule = .evenOdd\n```\n\n![cutlayer](https://raw.githubusercontent.com/lm2343635/ShapeView/master/screenshoots/cutlayer.png)\n\nThe range of the cut layer is outside of the shape's border and inside of the screen's border.\nAfter creating the cut layer, we set it as the mask of the shadow layer view.\n\n```Swift\nshadowLayerView.layer.mask = cutLayer\n```\n\nBy setting the cut layer for the shadow layer view, we get a hollow shape view with a shadow as the following picture.\n\n![hollow-shapelayer](https://raw.githubusercontent.com/lm2343635/ShapeView/master/screenshoots/hollow-shapelayer.png)\n\nNext, we create a container view above the shadow view, and use the same shape path to create a shape layer as the mask of this container view.\n\n```Swift\nlet shapeLayer = CAShapeLayer()\nshapeLayer.path = shapePath.cgPath\ncontainerView.layer.mask = shapeLayer\n```\n\nThe introduction above shows how to create a outer shadow, the method to create a inner shadow is same as the outer shadow.\nAt last, we get a customized shape view with the transparent background and shadow as shown in the demo screenshot.\n\n## Author\n\nlm2343635, lm2343635@126.com\n\n## License\n\nShapeView is available under the MIT license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flm2343635%2Fshapeview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flm2343635%2Fshapeview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flm2343635%2Fshapeview/lists"}