使用贝塞尔曲线路径创建自定义分段控件 (Swift)
Create custom segmented control using bezier path (Swift)
我正在尝试创建一个位于我的搜索控制器下方的自定义分段控件,如下面的模型所示
问题:
我在创建指示当前索引的尖针(看起来像这样:“^”)时遇到困难。
尝试解决方案:
多亏了下面问题的帮助,我能够让它看起来很接近,但我无法让指针显示出来
问题:
如何让我的代码看起来像我当前拥有的模型,并让指针随着分段控制器的当前索引移动?请参阅下面的代码
func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRectMake(0.0, 0.0, 1.0, segmentedController.frame.size.height)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
let image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image
}
func initializeSearchController() {
segmentedController.setTitleTextAttributes([NSFontAttributeName:UIFont(name: "Lato-Regular", size: 14)!,NSForegroundColorAttributeName:UIColor.init(red: 143/255, green: 142/255, blue: 148/255, alpha: 1.0)], forState:UIControlState.Normal)
segmentedController.setTitleTextAttributes([NSFontAttributeName:UIFont(name: "Lato-Bold", size: 14)!,NSForegroundColorAttributeName:UIColor.init(red: 93/255, green: 176/255, blue: 175/255, alpha: 1.0)], forState:UIControlState.Selected)
segmentedController.setDividerImage(self.imageWithColor(UIColor.clearColor()), forLeftSegmentState: UIControlState.Normal, rightSegmentState: UIControlState.Normal, barMetrics: UIBarMetrics.Default)
segmentedController.setBackgroundImage(self.imageWithColor(UIColor.clearColor()), forState:UIControlState.Normal, barMetrics:UIBarMetrics.Default)
segmentedController.setBackgroundImage(self.imageWithColor(UIColor.clearColor()), forState:UIControlState.Selected, barMetrics:UIBarMetrics.Default)
segmentedController.setTitle("Search", forSegmentAtIndex: 0)
segmentedController.setTitle("Meals", forSegmentAtIndex: 1)
for borderview in segmentedController.subviews {
let upperBorder: CALayer = CALayer()
upperBorder.backgroundColor = UIColor.init(red: 93/255, green: 176/255, blue: 175/255, alpha: 1.0).CGColor
upperBorder.frame = CGRectMake(0, borderview.frame.size.height-1, borderview.frame.size.width, 1.0);
borderview.layer.addSublayer(upperBorder);
}
}
最简单的方法就是作弊。您可以使用高度为 1 的 UIView 绘制实线,而不是使用贝塞尔曲线绘制线。在 PhotoShop 中将具有纯白色底部的三角形作为图像并将其放在线的顶部。现在要为位置设置动画,您可以更改其变换、更新其中心或使用自动布局约束,它将滑入新位置。例如:
UIView.animate(withDuration: 0.25) {
triangeImageView.center.x = selectedLabel.center.x
}
当然,您也可以使用 CAShapeLayer 以编程方式执行此操作。您将使用以下方式构建您的路径:
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: left, y: bottom))
bezierPath.addLine(to: CGPoint(x: centerX + triangleWidth/2, y: top))
bezierPath.addLine(to: CGPoint(x: centerX, y: top - triangleHeight))
bezierPath.addLine(to: CGPoint(x: centerX - triangleWidth/2, y: top))
bezierPath.addLine(to: CGPoint(x: left, y: top))
bezierPath.close()
然后您可以使用 CABasicAnimation 为从旧路径到新路径的路径设置动画。由于您以相同的顺序构建点,因此动画系统将插入位置并且三角形看起来会滑入位置。
我正在尝试创建一个位于我的搜索控制器下方的自定义分段控件,如下面的模型所示
问题:
我在创建指示当前索引的尖针(看起来像这样:“^”)时遇到困难。
尝试解决方案:
多亏了下面问题的帮助,我能够让它看起来很接近,但我无法让指针显示出来
问题:
如何让我的代码看起来像我当前拥有的模型,并让指针随着分段控制器的当前索引移动?请参阅下面的代码
func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRectMake(0.0, 0.0, 1.0, segmentedController.frame.size.height)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
let image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image
}
func initializeSearchController() {
segmentedController.setTitleTextAttributes([NSFontAttributeName:UIFont(name: "Lato-Regular", size: 14)!,NSForegroundColorAttributeName:UIColor.init(red: 143/255, green: 142/255, blue: 148/255, alpha: 1.0)], forState:UIControlState.Normal)
segmentedController.setTitleTextAttributes([NSFontAttributeName:UIFont(name: "Lato-Bold", size: 14)!,NSForegroundColorAttributeName:UIColor.init(red: 93/255, green: 176/255, blue: 175/255, alpha: 1.0)], forState:UIControlState.Selected)
segmentedController.setDividerImage(self.imageWithColor(UIColor.clearColor()), forLeftSegmentState: UIControlState.Normal, rightSegmentState: UIControlState.Normal, barMetrics: UIBarMetrics.Default)
segmentedController.setBackgroundImage(self.imageWithColor(UIColor.clearColor()), forState:UIControlState.Normal, barMetrics:UIBarMetrics.Default)
segmentedController.setBackgroundImage(self.imageWithColor(UIColor.clearColor()), forState:UIControlState.Selected, barMetrics:UIBarMetrics.Default)
segmentedController.setTitle("Search", forSegmentAtIndex: 0)
segmentedController.setTitle("Meals", forSegmentAtIndex: 1)
for borderview in segmentedController.subviews {
let upperBorder: CALayer = CALayer()
upperBorder.backgroundColor = UIColor.init(red: 93/255, green: 176/255, blue: 175/255, alpha: 1.0).CGColor
upperBorder.frame = CGRectMake(0, borderview.frame.size.height-1, borderview.frame.size.width, 1.0);
borderview.layer.addSublayer(upperBorder);
}
}
最简单的方法就是作弊。您可以使用高度为 1 的 UIView 绘制实线,而不是使用贝塞尔曲线绘制线。在 PhotoShop 中将具有纯白色底部的三角形作为图像并将其放在线的顶部。现在要为位置设置动画,您可以更改其变换、更新其中心或使用自动布局约束,它将滑入新位置。例如:
UIView.animate(withDuration: 0.25) {
triangeImageView.center.x = selectedLabel.center.x
}
当然,您也可以使用 CAShapeLayer 以编程方式执行此操作。您将使用以下方式构建您的路径:
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: left, y: bottom))
bezierPath.addLine(to: CGPoint(x: centerX + triangleWidth/2, y: top))
bezierPath.addLine(to: CGPoint(x: centerX, y: top - triangleHeight))
bezierPath.addLine(to: CGPoint(x: centerX - triangleWidth/2, y: top))
bezierPath.addLine(to: CGPoint(x: left, y: top))
bezierPath.close()
然后您可以使用 CABasicAnimation 为从旧路径到新路径的路径设置动画。由于您以相同的顺序构建点,因此动画系统将插入位置并且三角形看起来会滑入位置。