额...貌似挺长时间没有总结新知识了,最近在看swift,之前swift刚出来的时候大体看了一遍,后来时间长了没看加之swift2.0做了比较大的调整,公司项目也不是用swift写的,也就没怎么看了,谁成想忘的差不多了,趁公司最近项目不忙,有抽时间看了一丢丢,感觉这知识真是看一遍有一遍的收获,最近看了一个效果感觉挺好玩的.就是带有动画效果的TabBarItem,在这里总结一下.-----以上是为了给自己一个警醒,要多总结知识,加油,小青年,未来是你的!!!
首先,效果图如下
window = UIWindow(frame: ScreenBounds) window?.makeKeyAndVisible() //判断是否是第一次开启应用 let isFirstOpen = NSUserDefaults.standardUserDefaults().objectForKey("First") if isFirstOpen == nil { //第一次打开应用 window?.rootViewCOntroller= GuideViewController() NSUserDefaults.standardUserDefaults().setObject("First", forKey: "First") } else { //不是第一次打开应用 loadHomeViewController() }
第一次打开应用:
利用UICollectionView创建,1:先看cell中的内容,将imageView和Button放在collectionViewCell中,在这里需要注意,在前三页中没有"立即体验"button, 所以在自定义cell的时候需要一个函数在外面调用以改变button的隐藏与否:
func setNextBtnHidden(hidden:Bool) { nextBtn.hidden = hidden }
当滑动到第四页的时候,"立即体验"按钮出现点击按钮触发通知,通知controller进行界面跳转
func nextBtnClick() { NSNotificationCenter.defaultCenter().postNotificationName(GuideViewControllerDidFinish, object: nil) }
2:再看collectionViewController中的相关代码,collectionView需要layout:
let layout = UICollectionViewFlowLayout()
layout.minimumInteritemSpacing = 0 layout.minimumLineSpacing = 0 layout.itemSize = ScreenBounds.size layout.scrollDirection = .Horizontal
然后设置collectionView:
collectiOnView= UICollectionView(frame: ScreenBounds, collectionViewLayout: layout) collectionView?.delegate = self collectionView?.dataSource = self collectionView?.showsHorizOntalScrollIndicator= false collectionView?.showsVerticalScrollIndicator = false collectionView?.pagingEnabled = true collectionView?.bounces = false collectionView?.registerClass(GuideCollectionViewCell.self , forCellWithReuseIdentifier: cellIdentifier) view.addSubview(collectionView!)
注意:这一步在初始化collectionView的时候不要忘记registerCell
设置pageControl:
private var pageCOntroller= UIPageControl(frame: CGRectMake(0, ScreenHeight - 50, ScreenWidth, 20)) private func createPageControll() { pageController.numberOfPages = imageNames.count pageController.currentPage = 0 view.addSubview(pageController) }
然后实现collectionView的delegate和dataSource
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return imageNames.count } 返回一共有多少item
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath) as! GuideCollectionViewCell cell.newImage = UIImage(named: imageNames[indexPath.row]) if indexPath.row != imageNames.count - 1 { cell.setNextBtnHidden(true) } return cell } 设置自定义的cell ,并且在导航页不是最后一页的时候调用cell中设置Button Hidden的函数将Button隐藏
scrollView的代理方法:
func scrollViewDidEndDecelerating(scrollView: UIScrollView) { if scrollView.contentOffset.x == ScreenWidth * CGFloat(imageNames.count - 1) { let cell = collectionView?.cellForItemAtIndexPath(NSIndexPath(forRow: imageNames.count - 1, inSection: 0)) as! GuideCollectionViewCell cell.setNextBtnHidden(false) isHiddenNextButton = false } } 当滑动即将停止的时候,通过判断滑动页面的x的偏移量来设置cell中Button的隐藏或者显示
func scrollViewDidScroll(scrollView: UIScrollView) { if scrollView.contentOffset.x != ScreenWidth * CGFloat(imageNames.count - 1) && !isHiddenNextButton && scrollView.contentOffset.x > ScreenWidth * CGFloat(imageNames.count - 2) { let cell = collectionView?.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: NSIndexPath(forRow: imageNames.count - 1, inSection: 0)) as! GuideCollectionViewCell cell.setNextBtnHidden(true) isHiddenNextButton = true } pageController.currentPage = Int(scrollView.contentOffset.x / ScreenWidth + 0.5) } 当页面开始滑动时判断综合条件对cell中button进行设置,并且设置pageControl的currentPage
至此实现了启动导航页的collectionView实现的方法
接下来说一下有动画效果的TabBarItem的实现
底部的TabBarItem动画使用了三方框架RAMAnimatedTabBar,由于原来的框架 只能通过StoryBoard初始化控件,并且无法满足项目需求,所以源作者对框架进行了修改,在TabBarController初始化时,通过拦截Items,重新创建一套相同的View,并且在每个View上添加ImageView和Label,在View的点击事件中,控制动画即可.代码如下:
1.这是声明了一个选择TabBarItem时动画的协议 protocol RAMItemAnimationProtocol { func playAnimation(icon: UIImageView, textLabel:UILabel) func deselectAnimation(icon: UIImageView, textLabel: UILabel, defaultTextColor: UIColor) func selectedState(icon: UIImageView, textLabel: UILabel) }
2.遵守动画协议创建的动画类,主要是设置动画周期,item中选择的颜色 class RAMItemAnimation:NSObject, RAMItemAnimationProtocol { var duration: CGFloat = 0.6 var textSelectedColor: UIColor = UIColor.grayColor() var iconSelectedColor: UIColor? func playAnimation(icon: UIImageView, textLabel: UILabel) { } func deselectAnimation(icon: UIImageView, textLabel: UILabel, defaultTextColor: UIColor) { } func selectedState(icon: UIImageView, textLabel: UILabel) { } }
继承自RAMItemAnimation的类,主要实现父类中的协议方法,具体设置textLabel和UIImageView的动画周期和效果 class RAMBounceAnimation: RAMItemAnimation { override func playAnimation(icon: UIImageView, textLabel: UILabel) { playBounceAnimation(icon) textLabel.textColor = textSelectedColor } override func deselectAnimation(icon: UIImageView, textLabel: UILabel, defaultTextColor: UIColor) { textLabel.textColor = defaultTextColor if let icOnImage= icon.image { let renderImage = iconImage.imageWithRenderingMode(.AlwaysOriginal) icon.image = renderImage icon.tintColor = defaultTextColor } } override func selectedState(icon: UIImageView, textLabel: UILabel) { textLabel.textColor = textSelectedColor if let icOnImage= icon.image { let renderImage = iconImage.imageWithRenderingMode(.AlwaysOriginal) icon.image = renderImage icon.tintColor = textSelectedColor } } func playBounceAnimation(icon: UIImageView) { let bounceAnimation = CAKeyframeAnimation(keyPath: "transform.scale") bounceAnimation.values = [1.0, 1.4, 0.9, 1.15, 0.95, 1.02, 1.0] bounceAnimation.duration = NSTimeInterval(duration) bounceAnimation.calculatiOnMode= kCAAnimationCubic icon.layer.addAnimation(bounceAnimation, forKey: "bounceAnimation") if let icOnImage= icon.image { let renderImage = iconImage.imageWithRenderingMode(.AlwaysOriginal) icon.image = renderImage icon.tintColor = iconSelectedColor } } }
自定义UITabBarItem,声明UITabBarItem中的func deselectAnimation(icon: UIImageView, textLabel: UILabel)和 func selectedState(icon:UIImageView, textLabel:UILabel) 方法,以便在自定义UITabBarController中使用,其中animation是继承的RAMItemAnimation,可以调用父类中的方法,也就是父类中提前已经声明好的几个动画函数 class RAMAnimatedTabBarItem: UITabBarItem { var animation: RAMItemAnimation? var textColor = UIColor.grayColor() func playAnimation(icon: UIImageView, textLabel: UILabel) { guard let animation = animation else { print("add animation in UITabBarItem") return } animation.playAnimation(icon, textLabel: textLabel) } func deselectAnimation(icon: UIImageView, textLabel: UILabel) { animation?.deselectAnimation(icon, textLabel: textLabel, defaultTextColor: textColor) } func selectedState(icon:UIImageView, textLabel:UILabel) { animation?.selectedState(icon , textLabel: textLabel) } }
class AnimationTabBarController: UITabBarController { var iconsView:[(icon: UIImageView, textLabel: UILabel)] = [] var iconsImageName:[String] = ["v2_home", "v2_order", "shopCart", "v2_my"] var iconsSelectedImageName:[String] = ["v2_home_r", "v2_order_r", "shopCart_r", "v2_my_r"] override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } //创建承载TabBarItem的视图容器,里面是item中的titleLabel和UIImageView,将视图容器存入字典,以便在后续使用中可以分清是点了哪一个item func createViewContainers() -> [String: UIView] { var cOntainersDict= [String: UIView]() //tabbar的item是继承的自定义的RAMAnimatedTabBarItem,其中包含了动画设置的函数 guard let customItems = tabBar.items as? [RAMAnimatedTabBarItem] else { return containersDict } //根据item的个数创建视图容器,将视图容器放在字典中 for index in 0..count { let viewCOntainer= createViewContainer(index) containersDict["container\(index)"] = viewContainer } return containersDict } //根据index值创建每个的视图容器 func createViewContainer(index: Int) -> UIView { let viewWidth: CGFloat = ScreenWidth / CGFloat(tabBar.items!.count) let viewHeight: CGFloat = tabBar.height let viewCOntainer= UIView(frame: CGRectMake(viewWidth * CGFloat(index), 0, viewWidth, viewHeight)) viewContainer.backgroundColor = UIColor.clearColor() viewContainer.userInteractiOnEnabled= true tabBar.addSubview(viewContainer) viewContainer.tag = index //给容器添加手势,其实是自己重写了系统的item的功能,因为我们要在里面加入动画 let tap = UITapGestureRecognizer(target: self, action: "tabBarClick:") viewContainer.addGestureRecognizer(tap) return viewContainer } //创建items的具体内容 func createCustomIcons(containers: [String: UIView]) { if let items = tabBar.items { for (index, item) in items.enumerate() { assert(item.image != nil, "add image icon in UITabBarItem") guard let cOntainer= containers["container\(index)"] else { print("No container given") continue } container.tag = index let imageW:CGFloat = 21 let imageX:CGFloat = (ScreenWidth / CGFloat(items.count) - imageW) * 0.5 let imageY:CGFloat = 8 let imageH:CGFloat = 21 let icon = UIImageView(frame: CGRect(x: imageX, y: imageY, width: imageW, height: imageH)) icon.image = item.image icon.tintColor = UIColor.clearColor() let textLabel = UILabel () textLabel.frame = CGRectMake(0, 32, ScreenWidth / CGFloat(items.count), 49 - 32) textLabel.text = item.title textLabel.backgroundColor = UIColor.clearColor() textLabel.fOnt= UIFont.systemFontOfSize(10) textLabel.textAlignment = NSTextAlignment.Center textLabel.textColor = UIColor.grayColor() textLabel.translatesAutoresizingMaskIntoCOnstraints= false container.addSubview(icon) container.addSubview(textLabel) if let tabBarItem = tabBar.items { let textLabelWidth = tabBar.frame.size.width / CGFloat(tabBarItem.count) textLabel.bounds.size.width = textLabelWidth } let icOnsAndLabels= (icon:icon, textLabel:textLabel) iconsView.append(iconsAndLabels) item.image = nil item.title = "" if index == 0 { selectedIndex = 0 selectItem(0) } } } } //重写父类的didSelectItem override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) { setSelectIndex(from: selectedIndex, to: item.tag) } //选择item时item中内容的变化 func selectItem(index: Int) { let items = tabBar.items as! [RAMAnimatedTabBarItem] let selectIcon = iconsView[index].icon selectIcon.image = UIImage(named: iconsSelectedImageName[index])! items[index].selectedState(selectIcon, textLabel: iconsView[index].textLabel) } //根据选择的index值设置item中的内容并且执行动画父类中的方法 func setSelectIndex(from from: Int, to: Int) { selectedIndex = to let items = tabBar.items as! [RAMAnimatedTabBarItem] let fromIV = iconsView[from].icon fromIV.image = UIImage(named: iconsImageName[from]) items[from].deselectAnimation(fromIV, textLabel: iconsView[from].textLabel) let toIV = iconsView[to].icon toIV.image = UIImage(named: iconsSelectedImageName[to]) items[to].playAnimation(toIV, textLabel: iconsView[to].textLabel) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
最后MainTabBarController继承AnimationTabBarController
调用createViewContainers也就是父类中的方法
并且给tabBarController添加视图控制器
//MARK: - 初始化tabbar private func createMainTabBarChildViewController() { tabBarControllerAddChildViewController(HomeViewController(), title: "首页", imageName: "v2_home", selectedImageName: "v2_home_r", tag: 0) tabBarControllerAddChildViewController(MarketViewController(), title: "超市", imageName: "v2_order", selectedImageName: "v2_order_r", tag: 1) tabBarControllerAddChildViewController(ShopViewController(), title: "商店", imageName: "shopCart", selectedImageName: "shopCart", tag: 2) tabBarControllerAddChildViewController(MineViewController(), title: "我的", imageName: "v2_my", selectedImageName: "v2_my_r", tag: 3) } private func tabBarControllerAddChildViewController(childView: UIViewController, title: String, imageName: String, selectedImageName: String, tag: Int) { let vcItem = RAMAnimatedTabBarItem(title: title, image: UIImage(named: imageName), selectedImage: UIImage(named: selectedImageName)) vcItem.tag = tag vcItem.animation = RAMBounceAnimation() childView.tabBarItem = vcItem let navigatiOnVC= BaseNavigationController(rootViewController:childView) addChildViewController(navigationVC) } func tabBarController(tabBarController: UITabBarController, shouldSelectViewController viewController: UIViewController) -> Bool { let childArr = tabBarController.childViewControllers as NSArray let index = childArr.indexOfObject(viewController) if index == 2 { return false } return true }
这只是原作者项目中一个比较小的部分,原作者链接:http://www.jianshu.com/p/879f58fe3542
本Demo链接:https://github.com/iOSJason/AnimationTabBarItemSwiftDemo.git