iOS上的IBDesignable自定义垂直滑块
大家好,
前段时间,我们的设计师想要一个带有垂直滑块的批准页面。 此页面位于某些表单屏幕之后(用户在其中填写一些信息),并且通过向下滑动滑块可以看到其下面的页面。 同样,通过将滑块滑到底部,用户可以批准他填写的信息。
您可以在顶部看到一个丑陋的演示。 (完全由我设计designed)
对于此任务,我选择创建IBDesignable
自定义滑块,该滑块使用xib文件通过情节提要板在其他项目中重复使用它。 我的主要目的是能够在故事板上看到我的自定义滑块。 我希望获得有关自定义视图的即时视觉反馈,而不是编译和运行项目。
通过使用IBDesignable
您可以从情节IBDesignable
中实时编辑通过xib创建的自定义视图,我想这真是太酷了。
在这篇文章中,我们有2章:
- 第1章:如何创建使用xib的自定义垂直滑块
- 第2章:如何制作 包含
IBInspectable
元素 的IBDesignable
自定义视图
请注意,本文中将包含大量代码,我不想撰写单独的文章以保持完整性。 因此,您的职位很长。 希望您能找到对您有用的东西。
- 创建XIB
- 通过协议功能实现平移手势动作和与父视图的通讯
- 实现视图的实现方法
这些是我们要采取的步骤。 让我们开始使用滑块:
1.创建XIB
在此步骤中,我添加了一些屏幕截图,这些屏幕截图将对您有所帮助。 您也可以在Github上查看该项目以亲自查看。 您可以在文章末尾找到链接。
您可以在屏幕快照中查看视图层次结构及其IBOutlets
。
- SliderPath:所有项目均发生的位置。 平移手势使用此视图获取坐标反馈。
- thumbView:他认为您用手指滑动。 这也连接到手势识别器。
- destinationView:隐藏视图以检查拇指是否已到达目标。 您可以在底部选择的第一个屏幕截图中看到此视图。
- 我选择在xib上添加平移手势,并连接其动作和插座,如相关屏幕截图所示。
2.执行平移手势
相关的IBOutlets
和变量
var委托:KKVerticalSliderDelegate?
@IBOutlet弱fileprivate var slidePath:UIView!
@IBOutlet弱fileprivate var拇指:UIView!
@IBOutlet弱的fileprivate var目标:UIView!
@IBOutlet弱fileprivate var thumbTopConstraint:NSLayoutConstraint!
@IBOutlet fileprivate var panGesture:UIPanGestureRecognizer!
与父视图通信的协议。 您可以从它们的名称中了解这些方法的作用。
协议KKVerticalSliderDelegate {
func thumbReachedDestination()
func thumbCurrentPosition(_ position:CGFloat)
}
此计算的属性检查拇指是否已到达滑块的底部。
var isDestinationReached:Bool {
得到{
let distanceFromDestination:CGFloat = self.destination.center.y-self.thumb.center.y
返回distanceFromDestination <1
}
}
计算拇指的平移。 然后更改拇指的顶部约束以设置其新位置。
获得翻译后,我们将考虑上下边界以及拇指大小为原始翻译设置新的值。
因为约束随着AutoLayout不断变化,所以UIView.animate()
以很小的持续时间调用layoutIfNeeded()
以提供平滑的滑动效果。
func slideThumb(){让minY = CGFloat(0)
让maxY = sliderPath.bounds.size.height-thumb.bounds.size.height var translation = panGesture.translation(in:sliderPath)
var draggedDistance = thumbTopConstraint.constant + translation.y // //防止从路径边界向上移动
如果draggedDistance <0 {
draggedDistance = minY
translation.y + = thumbTopConstraint.constant-minY
}
//防止从路径范围下降
否则,如果draggedDistance> maxY {
draggedDistance = maxY
translation.y + = thumbTopConstraint.constant-maxY
}
其他{
translation.y = 0
} self.thumbTopConstraint.constant = draggedDistance
self.panGesture.setTranslation(translation,in:sliderPath)UIView.animate(withDuration:0.05,delay:0,options:.beginFromCurrentState,animations:{
self.layoutIfNeeded()
},完成:无)
}
通过更改其顶部约束将拇指返回到初始位置。
func returnInitialLocationAnimated(_动画:布尔){
thumbTopConstraint.constant = initialTopConstraint
如果(动画){
UIView.animate(withDuration:0.3,delay:0,options:.beginFromCurrentState,animations:{
self.layoutIfNeeded()
self.delegate?.thumbCurrentPosition(self.thumb.center.y)
},完成:无)
}
}
在xib中连接的panAction()
方法。 平移手势识别器触发此功能,该功能通过检查状态来决定要执行的操作。
如果状态已.changed
,请移动拇指并与父视图进行通信。
如果state为.ended
,则首先检查拇指是否在底部,然后通知父视图。 如果没有,则将拇指返回其初始位置。
@IBAction func panAction(){
如果panGesture.state == .changed {
slideThumb()
委托?.thumbCurrentPosition(self.thumb.center.y)
}
否则,如果panGesture.state == .ended {
如果isDestinationReached {
委托?.thumbReachedDestination()
}
其他{
returnInitialLocationAnimated(true)
}
}
}
3.实现创建视图的方法
在这一步中,我将展示通过从xib获取视图来准备视图的方法。
相关变量
var contentView:UIView?
var initialTopConstraint:CGFloat = 0.0
这些方法将从xib获取视图并将其应用于屏幕。 首先, awakeFromNib()
由系统调用。 loadViewFromNib()
从xib获取容器视图,然后arrangeView()
设置该视图的AutoLayout属性,然后将其添加为子视图。 didMoveToWindows()
是我设置一些初始属性的地方。
覆盖func awakeFromNib(){
super.awakeFromNib()
rangeView()
} funcrangeView(){
守卫let view = loadViewFromNib()else {return}
view.frame =界限
view.autoresizingMask = [.flexibleWidth,.flexibleHeight]
self.addSubview(view)
contentView =视图
} func loadViewFromNib()-> UIView? {
let bundle = Bundle(for:type(of:self))
let nib = UINib(nibName:String(描述:KKVerticalSlider.self),bundle:bundle)
返回nib.instantiate(withOwner:self,选项:nil).first作为? UIView
}覆盖func didMoveToWindow(){
//确保拇指始终从顶部开始
self.thumbTopConstraint.constant = 0
self.initialTopConstraint = self.thumbTopConstraint.constant;
}
首先,我们需要在@IBDesignable
开始时添加@IBDesignable
。
@IBDesignable
KKVerticalSlider类:UIView {
//您的代码...
}
如您从官方文档中看到的, prepareForInterfaceBuilder
使我们的自定义视图生效。 在运行时不会调用此方法,而仅由Interface Builder调用。 那不是很酷吗?
对于界面构建器,我们在为设备执行操作时会安排视图。 在arrangeView()
设置的contentView
是容器视图。 您可以在第一章的第三步中看到它。 这些代码使我们的视图在情节提要中可见。
覆盖func prepareForInterfaceBuilder(){
super.prepareForInterfaceBuilder()
rangeView()
contentView?.prepareForInterfaceBuilder()
}
聚一聚。 我有两个重要的技巧可以告诉你!
当您覆盖下面的方法时,请务必小心。 init(frame: CGRect)
方法有助于我们以编程方式创建自定义视图。 例如,我正在如下使用它。 如果在情节提要板上出现渲染问题,请首先检查这些方法。
覆盖init(frame:CGRect){
rangeView()
}是否需要init?(编码器aDecoder:NSCoder){
super.init(编码器:aDecoder)
}
另外,在加载视图时,请使用正确的捆绑包。 您可以在下面的StackOverflow线程中查看相关讨论。 这可以使您免于头痛。
无法呈现ClassName实例:代理在捆绑中装入笔尖时抛出异常
当Interface Builder呈现IBDesignable视图时,它使用一个助手应用程序来加载所有内容。 结果是…
stackoverflow.com
我正在使用IBInspectable
使滑块角变圆。 实施起来非常简单。 您可以在下面的代码中找到如何使用它的屏幕截图。
@IBInspectable var cornerRadius:CGFloat = 0 {
didSet {
layer.cornerRadius = cornerRadius
layer.masksToBounds = cornerRadius> 0
}
}
在屏幕截图中,您可以在右侧菜单的“属性”检查器中看到“转角半径”变量。 您可以现场更改它。 当拐角半径从20更改为35时,您会看到差异。就是这样,容易吗?
我希望这个loooooooong教程为您提供有关IBDesignable以及如何准备自定义视图的足够信息。 如果您想深入研究代码,并且还看到如何将此自定义滑块应用于视图控制器(可以通过对滑块的操作将其关闭),则可以在我的Github页面上签出项目。
mkeremkeskin / SliderForDismissing
SliderForDismissing –通过使用自定义IBDesignable垂直滑块演示关闭视图控制器。
github.com
感谢您阅读本文。
如果您要添加某些内容或需要帮助,请添加评论。
再见!