我正在创建一个图像拼贴应用程序。我将有多个 UIScrollView
的。 ScrollView 将具有自定义形状的边界,用户将能够动态更改它们相交的形状的角。 ScrollView 有 UIImageView
作为 subview 。
ScrollView 是其他 UIView 的 subview 。我申请了 CAShapeLayer
掩盖这些 UIView
的。这样我就可以毫无问题地屏蔽 ScrollView 。
但问题是,我只能滚动添加的最后一个 ScrollView 的内容。此外,我可以平移和缩放超出蒙版的边界。当我触摸作为蒙版的多边形边界时,我应该只能平移或缩放。
我试过;
scrollView.clipsToBounds = true
scrollView.layer.masksToBounds = true
func createMask(v: UIView, viewsToMask: [UIView], anchorPoint: CGPoint)
{
let frame = v.bounds
var shapeLayer = [CAShapeLayer]()
var path = [CGMutablePathRef]()
for i in 0...3 {
path.append(CGPathCreateMutable())
shapeLayer.append(CAShapeLayer())
}
//define frame constants
let center = CGPointMake(frame.origin.x + frame.size.width / 2, frame.origin.y + frame.size.height / 2)
let bottomLeft = CGPointMake(frame.origin.x, frame.origin.y + frame.size.height)
let bottomRight = CGPointMake(frame.origin.x + frame.size.width, frame.origin.y + frame.size.height)
switch frameType {
case 1:
// First view for Frame Type 1
CGPathMoveToPoint(path[0], nil, 0, 0)
CGPathAddLineToPoint(path[0], nil, bottomLeft.x, bottomLeft.y)
CGPathAddLineToPoint(path[0], nil, anchorPoint.x, bottomLeft.y)
CGPathAddLineToPoint(path[0], nil, anchorPoint.x, anchorPoint.y)
CGPathCloseSubpath(path[0])
// Second view for Frame Type 1
CGPathMoveToPoint(path[1], nil, anchorPoint.x, anchorPoint.y)
CGPathAddLineToPoint(path[1], nil, anchorPoint.x, bottomLeft.y)
CGPathAddLineToPoint(path[1], nil, bottomRight.x, bottomRight.y)
CGPathAddLineToPoint(path[1], nil, bottomRight.x, anchorPoint.y)
CGPathCloseSubpath(path[1])
// Third view for Frame Type 1
CGPathMoveToPoint(path[2], nil, 0, 0)
CGPathAddLineToPoint(path[2], nil, anchorPoint.x, anchorPoint.y)
CGPathAddLineToPoint(path[2], nil, bottomRight.x, anchorPoint.y)
CGPathAddLineToPoint(path[2], nil, bottomRight.x, 0)
CGPathCloseSubpath(path[2])
default:
break
}
for (key, view) in enumerate(viewsToMask) {
shapeLayer[key].path = path[key]
view.layer.mask = shapeLayer[key]
}
}
hitTest:withEvent:
像这样的方法,protocol CoolScrollViewDelegate: class {
var scrollViewPaths: [CGMutablePathRef] { get set }
}
class CoolScrollView: UIScrollView
{
weak var coolDelegate: CoolScrollViewDelegate?
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView?
{
if CGPathContainsPoint(coolDelegate?.scrollViewPaths[tag], nil, point, true) {
return self
} else {
return nil
}
}
}
hitTest:withEvent:
方法返回零。
我会同意@Kendel 在评论中的观点 - 首先它可能是创建 UIScrollView
的一种更简单的方法知道如何用特定形状掩盖自己的子类。将形状逻辑保留在 ScrollView 子类中将使事情保持整洁,并允许您轻松地将触摸限制在形状内(我稍后会谈到)。
从你的描述中很难确切地说出你的形状 View 应该如何表现,但作为一个简短的例子,你的 ShapedScrollView
可能看起来像这样:
import UIKit
class ShapedScrollView: UIScrollView {
// MARK: Types
enum Shape {
case First // Choose a better name!
}
// MARK: Properties
private let shapeLayer = CAShapeLayer()
var shape: Shape = .First {
didSet { setNeedsLayout() }
}
// MARK: Initializers
init(frame: CGRect, shape: Shape = .First) {
self.shape = shape
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// MARK: Layout
override func layoutSubviews() {
super.layoutSubviews()
updateShape()
}
// MARK: Updating the Shape
private func updateShape() {
// Disable core animation actions to prevent changes to the shape layer animating implicitly
CATransaction.begin()
CATransaction.setDisableActions(true)
if bounds.size != shapeLayer.bounds.size {
// Bounds size has changed, completely update the shape
shapeLayer.frame = CGRect(origin: contentOffset, size: bounds.size)
shapeLayer.path = pathForShape(shape).CGPath
layer.mask = shapeLayer
} else {
// Bounds size has NOT changed, just update origin of shape path to
// match content offset - makes it appear stationary as we scroll
var shapeFrame = shapeLayer.frame
shapeFrame.origin = contentOffset
shapeLayer.frame = shapeFrame
}
CATransaction.commit()
}
private func pathForShape(shape: Shape) -> UIBezierPath {
let path = UIBezierPath()
switch shape {
case .First:
// Build the shape path, whatever that might be...
// path.moveToPoint(...)
// ...
}
return path
}
}
UIView
提供了一种有用的 HitTest 方法,可让您指定是否应将特定点视为该 View 的“内部”:pointInside(_:withEvent
.只需将以下覆盖添加到 ShapedScrollView
:override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
return CGPathContainsPoint(shapeLayer.path, nil, layer.convertPoint(point, toLayer: shapeLayer), false)
}
point
(转换为形状图层的坐标系)在形状的内部 path
,则将其视为在 View 内;否则将其视为在 View 外。”ShapedScrollContainerView: UIView
来采用此技术。与 scrollView
属性(property)。然后,如上将形状 mask 应用到容器上,并再次使用 pointInside(_:withEvent
测试它是否应该响应特定的接触点。
关于swift - 仅当触摸位于自定义形状内时,如何使 UIScrollView 可滚动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31899016/
欢迎光临 OGeek|极客世界-中国程序员成长平台 (http://jike.in/) | Powered by Discuz! X3.4 |