Skip to content

Commit 77fab13

Browse files
committed
Increase the mask effect interface.
1 parent 0b7d3ed commit 77fab13

File tree

2 files changed

+187
-28
lines changed

2 files changed

+187
-28
lines changed

LCSlideMenu/LCSlideMenu.swift

Lines changed: 181 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import UIKit
1414
/// - normal: 默认
1515
/// - gradient: 渐变颜色
1616
/// - transfrom: 放大
17+
/// - cover: 遮罩
1718
public enum LCSlideMenuTitleStyle {
1819
case normal
1920
case gradient
2021
case transfrom
22+
case cover
2123
}
2224

2325
/// 选择菜单指示器风格
@@ -54,6 +56,12 @@ open class LCSlideMenu: UIView {
5456
/// Item的间距
5557
private var itemMargin: CGFloat = 15.0
5658

59+
/// 遮罩高度
60+
private var coverHeight : CGFloat = 25.0
61+
62+
/// 遮罩内部间距
63+
private var coverInsetMargin : CGFloat = 10.0
64+
5765
/// 选中的索引
5866
fileprivate var itemSelectedIndex: Int = 0
5967

@@ -66,6 +74,14 @@ open class LCSlideMenu: UIView {
6674
/// 伸缩动画的偏移量
6775
fileprivate let indicatorAnimatePadding: CGFloat = 8.0
6876

77+
// MARK: - 懒加载视图
78+
79+
/// 指示器视图
80+
public lazy var indicatorView: UIView = UIView()
81+
82+
/// 内容视图
83+
fileprivate lazy var mainScrollView: UIScrollView = UIScrollView()
84+
6985
/// 菜单栏
7086
fileprivate lazy var tabScrollView: UIScrollView = {
7187
let tabScrollView = UIScrollView(frame: self.bounds)
@@ -75,16 +91,10 @@ open class LCSlideMenu: UIView {
7591
return tabScrollView
7692
}()
7793

78-
/// 内容视图
79-
fileprivate lazy var mainScrollView: UIScrollView = UIScrollView()
80-
81-
/// 指示器视图
82-
public lazy var indicatorView: UIView = UIView()
83-
8494
/// 底部长线
8595
private lazy var scrollLine: UIView = { [unowned self] in
8696
let scrollLine = UIView()
87-
let scrollLineH: CGFloat = 0.5 // 底部长线的高度
97+
let scrollLineH: CGFloat = 0.5
8898
scrollLine.backgroundColor = UIColor.lightGray
8999
scrollLine.frame = CGRect(x: 0, y: self.bounds.height - scrollLineH, width: self.bounds.width, height: scrollLineH)
90100
return scrollLine
@@ -96,6 +106,13 @@ open class LCSlideMenu: UIView {
96106
blurView.frame = self.bounds
97107
return blurView
98108
}()
109+
110+
/// 遮罩视图
111+
private lazy var coverView : UIView = {
112+
let coverView = UIView()
113+
coverView.backgroundColor = coverColor
114+
return coverView
115+
}()
99116

100117
/// 标题字体
101118
public var itemFont: UIFont = UIFont.systemFont(ofSize: 13) {
@@ -104,6 +121,33 @@ open class LCSlideMenu: UIView {
104121
}
105122
}
106123

124+
/// 是否显示指示器视图
125+
public var isShowIndicatorView: Bool = false {
126+
didSet{ // 监听数值isShowIndicatorView的改变
127+
if !isShowIndicatorView {
128+
indicatorView.isHidden = true
129+
}
130+
configIndicatorView()
131+
}
132+
}
133+
134+
/// 是否需要遮罩
135+
public var isNeedMask: Bool = false {
136+
didSet { // 监听数值isNeedMask的改变
137+
if !isNeedMask {
138+
coverView.isHidden = true
139+
}
140+
configCoverView()
141+
}
142+
}
143+
144+
/// 遮罩颜色
145+
public var coverColor: UIColor = UIColor(white: 0.4, alpha: 0.5) {
146+
didSet {
147+
148+
}
149+
}
150+
107151
/// 选中颜色
108152
public var selectedColor: UIColor = .red {
109153
didSet {
@@ -118,14 +162,14 @@ open class LCSlideMenu: UIView {
118162
}
119163
}
120164

121-
/// 下标距离底部距离
165+
/// 指示器距离底部距离
122166
public var bottomPadding: CGFloat = 2.0 {
123167
didSet {
124168

125169
}
126170
}
127171

128-
/// 下标高度
172+
/// 指示器高度
129173
public var indicatorHeight: CGFloat = 2.0 {
130174
didSet{
131175

@@ -151,7 +195,7 @@ open class LCSlideMenu: UIView {
151195
addSubview(scrollLine)
152196

153197
configTabScrollView()
154-
configIndicatorView()
198+
// configIndicatorView()
155199
}
156200

157201

@@ -213,19 +257,23 @@ open class LCSlideMenu: UIView {
213257
// 遍历titles
214258
for (index,title) in titles.enumerated() {
215259

216-
// 创建Label, 并设置其相关属性
260+
// 1.创建Label, 并设置其相关属性
217261
let label = UILabel()
218262
label.text = title
219263
label.font = itemFont
264+
label.isUserInteractionEnabled = true
265+
label.textAlignment = .center
266+
220267
// 如果标签索引为:选中索引, 设置Label颜色为: 选中颜色, 否则为: 未选中颜色
221268
label.textColor = index == itemSelectedIndex ? selectedColor : unSelectedColor
222-
label.isUserInteractionEnabled = true
223269

224270
// 计算title长度
225271
// 根据文字来计算宽度
226272
let size = (title as NSString).size(withAttributes: [NSAttributedStringKey.font : itemFont])
227-
228-
label.frame = CGRect(x: originX, y: 0, width: size.width, height: self.bounds.height)
273+
274+
// 2.计算位置
275+
label.frame = CGRect(x: originX, y: 0, width: size.width + itemMargin, height: self.bounds.height)
276+
229277
// 添加tap手势
230278
let tap = UITapGestureRecognizer(target: self, action: #selector(labelClicked(_:)))
231279
label.addGestureRecognizer(tap)
@@ -235,12 +283,11 @@ open class LCSlideMenu: UIView {
235283

236284
originX = label.frame.maxX + itemMargin * 2
237285
}
238-
// 设置scrollView的滚动范围
286+
// 3.设置scrollView的滚动范围
239287
tabScrollView.contentSize = CGSize(width: originX - itemMargin, height: self.bounds.height)
240-
241288
tabScrollView.addSubview(indicatorView)
242289

243-
//如果item的长度小于self的width,就重新计算margin排版
290+
//如果item的长度小于当前视图的width,就重新计算margin排版
244291
if tabScrollView.contentSize.width < self.bounds.width {
245292
updateLabelsFrame()
246293
}
@@ -261,6 +308,23 @@ open class LCSlideMenu: UIView {
261308
indicatorView.layer.masksToBounds = true
262309
}
263310

311+
/// 配置遮罩视图
312+
private func configCoverView() {
313+
314+
tabScrollView.insertSubview(coverView, at: 0)
315+
316+
guard let titleLabel = itemsLabel.first else { return }
317+
let coverX : CGFloat = titleLabel.frame.origin.x
318+
let coverW : CGFloat = titleLabel.frame.width
319+
let coverH : CGFloat = coverHeight
320+
let coverY : CGFloat = (titleLabel.frame.height - coverH) * 0.5 // 遮罩视图Y值
321+
322+
coverView.frame = CGRect(x: coverX, y: coverY, width: coverW, height: coverH)
323+
coverView.layer.cornerRadius = coverHeight * 0.4 // 设置圆角
324+
coverView.layer.masksToBounds = true
325+
}
326+
327+
264328
/// 监听item点击事件
265329
///
266330
/// - Parameter gesture: 手势
@@ -281,6 +345,8 @@ open class LCSlideMenu: UIView {
281345

282346
changeIndicatorViewPosition(currentIndex, old: itemSelectedIndex)
283347

348+
changeCoverViewPosition(currentIndex, old: itemSelectedIndex)
349+
284350
resetTabScrollViewContentOffset(currentLabel)
285351

286352
resetMainScrollViewContentOffset(itemSelectedIndex)
@@ -322,6 +388,28 @@ open class LCSlideMenu: UIView {
322388
self.indicatorView.frame = indicatorFrame
323389
}
324390
}
391+
392+
393+
394+
/// 改变coverView的位置
395+
///
396+
/// - Parameters:
397+
/// - current: 当前标题索引
398+
/// - old: 之前标题索引
399+
private func changeCoverViewPosition(_ current: Int, old: Int) {
400+
401+
// 获取之前label的尺寸
402+
let frame = itemsLabel[old].frame
403+
404+
/// 遮罩视图的Frame
405+
let coverFrame = CGRect(x: frame.origin.x, y: coverView.frame.origin.y, width: frame.size.width, height: coverHeight)
406+
407+
// 动画改变 coverView 的位置
408+
UIView.animate(withDuration: 0.25) {
409+
self.coverView.frame = coverFrame
410+
}
411+
412+
}
325413

326414
/// 当item过少时,更新itemLabel位置
327415
private func updateLabelsFrame() {
@@ -353,15 +441,18 @@ open class LCSlideMenu: UIView {
353441
case .normal: // 默认
354442
leftItem.textColor = progress <= 0.5 ? selectedColor : unSelectedColor
355443
rightItem.textColor = progress <= 0.5 ? unSelectedColor : selectedColor
356-
default:
444+
case .cover: // 遮罩
445+
leftItem.textColor = averageColor(currentColor: selectedColor, oldColor: unSelectedColor, percent: progress)
446+
rightItem.textColor = averageColor(currentColor: unSelectedColor, oldColor: selectedColor, percent: progress)
447+
default: // .transfrom:放大
357448
if progress <= 0.5 { // 如果进度 < 0.5
358449
leftItem.textColor = selectedColor
359450
rightItem.textColor = unSelectedColor
360451
UIView.animate(withDuration: 0.25, animations: {
361452
leftItem.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
362453
rightItem.transform = CGAffineTransform.identity
363454
})
364-
} else {
455+
}else {
365456
leftItem.textColor = unSelectedColor
366457
rightItem.textColor = selectedColor
367458
UIView.animate(withDuration: 0.25, animations: {
@@ -437,7 +528,7 @@ open class LCSlideMenu: UIView {
437528

438529
let leftItem = itemsLabel[leftIndex]
439530
let rightItem = itemsLabel[rightIndex]
440-
531+
/// 总得移动距离
441532
let totalSpace = rightItem.center.x - leftItem.center.x
442533
indicatorView.center = CGPoint(x:leftItem.center.x + totalSpace * ratio, y: indicatorView.center.y)
443534
}
@@ -463,21 +554,80 @@ open class LCSlideMenu: UIView {
463554

464555
let leftItem = itemsLabel[leftIndex]
465556
let rightItem = itemsLabel[rightIndex]
557+
558+
var frame = self.indicatorView.frame
559+
let leftItemWidth: CGFloat = leftItem.frame.width
560+
let leftItemFrameMinX: CGFloat = leftItem.frame.minX
561+
let rightItemWidth: CGFloat = rightItem.frame.width
562+
let rightItemFrameMaxX: CGFloat = rightItem.frame.maxX
563+
466564
/// 间距
467565
let distance: CGFloat = indicatorType == .stretch ? 0 : indicatorAnimatePadding
468-
var frame = self.indicatorView.frame
469-
let maxWidth = rightItem.frame.maxX - leftItem.frame.minX - distance * 2
566+
567+
/// 最大宽度: 右边Item最大X值 - 左边Item最小X值 - 2倍间距
568+
let maxWidth = rightItemFrameMaxX - leftItemFrameMinX - distance * 2
569+
470570
if ratio <= 0.5 {
471-
frame.size.width = leftItem.frame.width + (maxWidth - leftItem.frame.width) * (ratio / 0.5)
472-
frame.origin.x = leftItem.frame.minX + distance * (ratio / 0.5)
571+
frame.size.width = leftItemWidth + (maxWidth - leftItemWidth) * (ratio / 0.5)
572+
frame.origin.x = leftItemFrameMinX + distance * (ratio / 0.5)
473573
} else {
474-
frame.size.width = rightItem.frame.width + (maxWidth - rightItem.frame.width) * ((1 - ratio) / 0.5)
475-
frame.origin.x = rightItem.frame.maxX - frame.size.width - distance * ((1 - ratio) / 0.5)
574+
frame.size.width = rightItemWidth + (maxWidth - rightItemWidth) * ((1 - ratio) / 0.5)
575+
frame.origin.x = rightItemFrameMaxX - frame.size.width - distance * ((1 - ratio) / 0.5)
476576
}
477577

478578
self.indicatorView.frame = frame
479579
}
480580

581+
582+
/// 处理cover状态
583+
///
584+
/// - Parameter offsetX: 偏移量
585+
fileprivate func handleCoverType(_ offsetX: CGFloat) {
586+
587+
if offsetX <= 0 {
588+
//左边界
589+
leftIndex = 0
590+
rightIndex = 0
591+
} else if offsetX >= mainScrollView.contentSize.width {
592+
//右边界
593+
leftIndex = itemsLabel.count - 1
594+
rightIndex = leftIndex
595+
} else {
596+
//中间
597+
leftIndex = Int(offsetX / mainScrollView.bounds.width)
598+
rightIndex = leftIndex + 1
599+
}
600+
/// 比例
601+
let ratio = offsetX / mainScrollView.bounds.width - CGFloat(leftIndex)
602+
if ratio == 0 { return }
603+
604+
let leftItem = itemsLabel[leftIndex]
605+
let rightItem = itemsLabel[rightIndex]
606+
607+
var frame = self.coverView.frame
608+
let leftItemWidth: CGFloat = leftItem.frame.width
609+
let leftItemFrameMinX: CGFloat = leftItem.frame.minX
610+
let rightItemWidth: CGFloat = rightItem.frame.width
611+
let rightItemFrameMaxX: CGFloat = rightItem.frame.maxX
612+
613+
/// 间距
614+
let distance: CGFloat = titleStyle == .cover ? 0 : 8
615+
616+
/// 最大宽度: 右边Item最大X值 - 左边Item最小X值 - 2倍间距
617+
let maxWidth = rightItem.frame.maxX - leftItem.frame.minX - distance * 2
618+
619+
if ratio <= 0.5 {
620+
frame.size.width = leftItemWidth + (maxWidth - leftItemWidth) * (ratio / 0.5)
621+
frame.origin.x = leftItemFrameMinX + distance * (ratio / 0.5)
622+
} else {
623+
frame.size.width = rightItemWidth + (maxWidth - rightItemWidth) * ((1 - ratio) / 0.5)
624+
frame.origin.x = rightItemFrameMaxX - frame.size.width - distance * ((1 - ratio) / 0.5)
625+
}
626+
self.coverView.frame = frame
627+
628+
}
629+
630+
481631
/// 渐变颜色
482632
///
483633
/// - Parameters:
@@ -517,7 +667,7 @@ extension LCSlideMenu: UIScrollViewDelegate {
517667

518668
// MARK: 当scrollview处于滚动状态时, offset发生改变,就会调用此函数. 直到停止.
519669
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
520-
670+
521671
/// 滚动视图横向(x)移动数值
522672
let offsetX = scrollView.contentOffset.x
523673
switch indicatorType {
@@ -529,6 +679,10 @@ extension LCSlideMenu: UIScrollViewDelegate {
529679
handleFollowTextIndicatorType(offsetX)
530680
}
531681

682+
if titleStyle == .cover {
683+
handleCoverType(offsetX)
684+
}
685+
532686
//计算偏移的相对位移
533687
let relativeLacation = mainScrollView.contentOffset.x / mainScrollView.frame.width - CGFloat(leftIndex)
534688
if relativeLacation == 0 { return }

LCSlideMenuExample/ViewController.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class ViewController: UIViewController {
1818

1919
private func example() {
2020

21-
let titles = ["头条", "精选", "轻松一刻", "娱乐", "新时代", "手机","体育", "视频", "财经", "汽车","军事", "房产", "健康", "彩票", "搞笑"]
21+
let titles = ["Apple", "Banana", "Watermelon", "Orange", "Lemon", "Pear","Strawberry", "Sapodilla", "Haw", "Grape","Mango", "Plum", "Persimmon", "Fig", "Betelnut"]
2222

2323
var controllers: [UIViewController] = []
2424

@@ -36,6 +36,11 @@ class ViewController: UIViewController {
3636
let slideMenu = LCSlideMenu(frame: CGRect(x: 0, y: 64, width: view.frame.width, height: 40), titles: titles, childControllers: controllers)
3737
slideMenu.indicatorType = .stretch
3838
slideMenu.titleStyle = .gradient
39+
slideMenu.isShowIndicatorView = true
40+
slideMenu.isNeedMask = false
41+
slideMenu.selectedColor = .red
42+
slideMenu.unSelectedColor = .black
43+
slideMenu.indicatorView.backgroundColor = .red
3944
view.addSubview(slideMenu)
4045
}
4146
}

0 commit comments

Comments
 (0)