【IOS|IOS 滑动菜单】完整Demo地址
效果图
文章图片
[滑动菜单效果图-github](https://github.com/AllenOoo/SliderMenu-CollectionView)
结构图
文章图片
结构图.png Item的属性、状态
- scaleFloat,Item缩放系数。
- highlightColor,高亮颜色。
- 原始状态:scaleFloat = 1,颜色设置的初始颜色
- 正在放大但不是最大:1 < scaleFloat < Max,颜色为透明度为(scaleFloat/Max)的highlightColor
- 放大至最大:scaleFloat = Max,颜色 = highlightFloat
UIView: 和外部控件联动时控制各Item的状态
代码 Item中,只通过一个scaleFloat属性来控制Item的所有状态这样外部使用不容易乱!
override var scaleFloat: Double {
didSet {var scaleColorFloat = scaleFloat;
var titleColor:UIColor!
if scaleColorFloat < 1.05 {
titleColor = UIColor.whiteColor()
} else {
if scaleColorFloat < 1.20 {
scaleColorFloat = 1.2
}titleColor = highlightColor.colorWithAlphaComponent(CGFloat(scaleColorFloat/YZButtonScaleMaxFloat))
}
self.setTitleColor(titleColor, forState: .Normal)
if isNeededAnimation {
if scaleFloat >= YZButtonScaleMaxFloat {
UIView.animateWithDuration(YZButtonTransAnimationInterval, animations: {
self.transform = self.transScale(YZButtonScaleMaxFloat)
})
} else {
if scaleFloat <= 1.05 {
UIView.animateWithDuration(YZButtonTransAnimationInterval, animations: {
self.transform = self.transBack()
})
}
}
} else {
if scaleFloat > YZButtonScaleMaxFloat - 0.05 {
self.transform = self.transScale(YZButtonScaleMaxFloat)
} else {
if scaleFloat <= 1.05 {
self.transform = self.transBack()
} else {
self.transform = self.transScale(scaleFloat)
}
}
}
isNeededAnimation = false
}
}
UIView中的方法
- 通过手势滑动距离给当前高亮Item和两边的Item做状态设置
func itemScaledByDistance(distance: Double) {/// 给对应的item进行缩放
let scaleFloat = (fabs(distance)/Double(self.frame.width))*YZButtonScaleMaxFloat
let currentItem = YZButtons[index]
let nextItem : YZButton?
if distance > 0 {
// 左
if index <= 0 {
nextItem = YZButton.init(frame: CGRectZero)
} else {
nextItem = YZButtons[index-1]
}
} else {
if index >= YZButtons.count-1 {
nextItem = YZButton.init(frame: CGRectZero)
} else {
nextItem = YZButtons[index+1]
}
}
nextItem?.scaleFloat = 1 + scaleFloat
currentItem?.scaleFloat = YZButtonScaleMaxFloat - scaleFloat
}
2.手势结束设定对应Item设定最终状态
func sliderMenuWillScrollToIndex(targetIndex: NSInteger) {
let lastItem : YZButton?
let nextItem : YZButton?
if targetIndex == 0 {
nextItem = YZButtons[targetIndex + 1]
lastItem = YZButton.init(frame: CGRectZero)
} else if targetIndex >= YZButtons.count - 1 {
nextItem = YZButton.init(frame: CGRectZero)
lastItem = YZButtons[targetIndex - 1]
} else {
nextItem = YZButtons[targetIndex + 1]
lastItem = YZButtons[targetIndex - 1]
}
/// 返回初始状态
lastItem?.scaleFloat = YZButtonScaleMinFloat
nextItem?.scaleFloat = YZButtonScaleMinFloat
index = targetIndex;
}
CollectionView中需要传给菜单的数据
1.捕获手势状态
self.panGestureRecognizer.addTarget(self, action: #selector(panGestureActionInState(_:)))func panGestureActionInState(gesture: UIPanGestureRecognizer) {
if gesture.state == .Changed {
self.gestureDelegate.collectionView(self, panning: gesture)
}
if gesture.state == .Ended {
self.gestureDelegate.collectionView(self, didEndPan: gesture, to: targetIndex)
}
}
2.将要停止的目标位置
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) {
let offsetX = targetContentOffset.memory.x
targetIndex = lroundf(Float(offsetX/self.frame.width))
}
最后上下联动
/// 在菜单中做点击操作
func didSelectedAtIndex(index: NSInteger, animated: Bool) {
collection.scrollToItemAtIndexPath(NSIndexPath.init(forRow: index, inSection: 0), atScrollPosition: .CenteredHorizontally, animated: animated)
}
/// 滑动CollectionView的过程
func collectionView(collectionView: SliderMenuInfoView, panning pan: UIPanGestureRecognizer) {
sliderMenu.itemScaledByDistance(Double(pan.translationInView(collectionView).x))
}
/// 手势停止时
func collectionView(collectionView: SliderMenuInfoView, didEndPan pan: UIPanGestureRecognizer, to targetIndex: NSInteger) {
sliderMenu.sliderMenuWillScrollToIndex(targetIndex)
}
完整Demo地址