iOS swift 引导页(镂空设计)引导操作下一步样式(引导样式为collectionview
带定位)
整体提示的代码
dropBox(使用梯子显示)WorkBenchTipView.swift
https://www.dropbox.com/s/d7skghoi6htp5g5/WorkBenchTipView.swift?dl=0
设计样式
小屏手机
大屏手机
第一个如果顶部没有东西分别显示
设计方案:
**整体:**在该页面的请求都完成后,在window
层addsubview
一个与占满屏幕的view,该view的背景颜色为全黑50%透明,得到一个阴影效果
高亮显示:其实就是切割当前的view,用到了layer层,原理为该整体view的layer.mask
使用特质的CAShapeLayer()
CAShapeLayer
的path
为一个特制的切割样式UIBezierPath
制作UIBezierPath
为添加一个固定位置的镂空的设计
path.append(UIBezierPath(roundedRect: newFrame, cornerRadius: 8).reversing())
其他引导样式就位普通的addsubview
进行添加
难点为下一步的操作: 其实就是下一步的时候把layer.mask
使用新的CAShapeLayer
。其他引导样式更改所属的位置。如果该指示的collectionview的位置不在当前屏幕时,需要先collectionview跳到指定的位置collectionView.scrollToItem(
,然后获取当前collectionview的scrollview的滑动位置collectionView.contentOffset.y
。从而可以计算出引导显示的位置。
提示控件显示:因为采用的是镂空减法操作,很难把握位置在哪,整体的控件使用的静态布局,直接改.frame
,内部的位置相对于整体控件的,自动布局相对方便点。
核心代码
整体嵌入
其中可以不用使用层级最高的keyWindow
,键盘、弹窗默认是keyWindow
层级的。
let window = UIApplication.shared.keyWindow
let tipView = WorkBenchTipView(frame: window!.bounds)
tipView.scrollCallback = { [weak self] index in
let offsetY = self?.workbenchView.collectionViewJump(index: index)
tipView.scrollOffsetY = offsetY ?? 0.0
}
let frameList = workbenchView.getSessionHeight()
tipView.hasAd = !(workbenchView.adList?.isEmpty ?? false)
tipView.maskFrame = [0: frameList[0], 1: frameList[1], 2: frameList[2]]
window?.addSubview(tipView)
切割样式:切割出高亮部分
index 为步骤
path 为整体的样式
frame 为切割的位置
scrollOffsetY是VC传过来关于collectionview的滑动距离
shapeLayer就是var shapeLayer = CAShapeLayer()
// 创建整体的待切割样式
if index == 0 {
path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height))
} else {
path.removeAllPoints()
path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height))
}
if index < 3 {
// 切割的位置
guard let frame = maskFrame[index] else { return }
let text = tipTitle[index]
let contentY = frame.maxY
// 切割的位置>当前屏幕回调,会返回新的scrollOffsetY
if (contentY) > (KSCREENHEIGHT - kStatusAndNavBarH - kTabBarHeight) {
scrollCallback?(index)
}
var newFrame = frame
newFrame.origin.y -= scrollOffsetY
path.append(UIBezierPath(roundedRect: newFrame, cornerRadius: 8).reversing())
shapeLayer.path = path.cgPath
layer.mask = shapeLayer
}
下一步操作 难点
计算摆放的位置问题,由于是标记的是collectionview。
1、需要知道每个session
的位置,iphone6一行最多只能显示4个,iphone11一行最多显示5个。这导致行数不一样显示的session位置也不一样。有广告栏和没广告栏的位置显示不一样,有刘海屏和没刘海屏的显示位置也不一样。
2、知道当前滑了多少:因为显示不完整的时候要滑到相应的位置再显示。
核心代码:
存储位置:在collectionview的view上获取
kStatusAndNavBarH
为刘海屏部分+顶部navigationbar
的高度。
(KSCREENWIDTH / 750) * 276 + 20
为广告栏高度
public func getSessionHeight() -> [CGRect] {
var result: [CGRect] = []
var yPostion: CGFloat = kStatusAndNavBarH
if isExperience != true {
if adList != nil && adList?.count ?? 0 > 0 {
yPostion += (KSCREENWIDTH / 750) * 276 + 20
}
}
dataArr.forEach { itemList in
let rowCount = Int((KSCREENWIDTH - 30)/75)
let rowLine = Int(ceil(Double(itemList.list.count) / Double(rowCount)))
let sessionHeight: CGFloat = 40.0 + CGFloat(rowLine) * 88.0
result.append(CGRect(x: 10, y: yPostion, width: KSCREENWIDTH - 20, height: sessionHeight))
yPostion += sessionHeight
}
return result
}
根据获取的存储位置来更新UI
// 传入frame,布局遮罩
public var maskFrame: [Int: CGRect] = [:] {
didSet {
updatePath()
}
}
可以根据遮罩的定位布局提示UI的位置。