仿转转首页Banner图

作者: z小志 | 来源:发表于2018-04-23 14:42 被阅读41688次
    4月-23-2018 14-04-47.gif

    实现效果

    • 当banner滚动的时候 首先会缩放当前以及上一个或下一个banner图,
    • 当banner滚动时会,背景会随滚动系数变化

    部分实现

    1、缩放(自动滚动)

       自动滚动开始时 缩放当前cell
      @objc func automaticScroll(){
            if totalItemCount == 0{return}
            let currentIndex = self.currentIndex()  
            let targetIndex = currentIndex + 1
            
            let cell = banner.cellForItem(at: IndexPath.init(row: currentIndex, section: 0))
            UIView.animate(withDuration: 0.2, animations: {
                cell?.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
            }) { (finish) in
                self.scrollToIndex(targetIndex: targetIndex)
            }
        }
    //滚动动画结束后还原 当前 以及 前后的cell
    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
            self.autoScrollIndex = self.currentIndex()
            
            let cell1 = banner.cellForItem(at: IndexPath.init(row: self.autoScrollIndex - 1 < 0 ? totalItemCount :  self.autoScrollIndex - 1, section: 0))
            
            let cell2 = banner.cellForItem(at: IndexPath.init(row: self.autoScrollIndex , section: 0))
            let cell3 = banner.cellForItem(at: IndexPath.init(row: self.autoScrollIndex + 1 > totalItemCount ? totalItemCount/2 : 0, section: 0))
            
            UIView.animate(withDuration: 0.2) {
                cell1?.transform = CGAffineTransform(scaleX: 1, y: 1)
                cell2?.transform = CGAffineTransform(scaleX: 1, y: 1)
                cell3?.transform = CGAffineTransform(scaleX: 1, y: 1)
            }
        }
      
    

    2、缩放(拖动)

    if scrollView.isDragging || scrollView.isDecelerating{
                let itemIndex = self.pageControlIndexWithCurrentCellIndex(index: draggingIndex)
                //向左
                if lastContentOffset > curretContentOffset{
    
                    let cell1 = banner.cellForItem(at: IndexPath.init(row: self.draggingIndex, section: 0))
                    let cell2 = banner.cellForItem(at: IndexPath.init(row: self.draggingIndex - 1 < 0 ? totalItemCount: self.draggingIndex - 1, section: 0))
                    
                    UIView.animate(withDuration: 0.1) {
                        cell1?.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
                        cell2?.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
                    }
                    let topIndex = itemIndex - 1 < 0 ? self.banners.count - 1 : itemIndex - 1
                    let bottomIndex = itemIndex
                    self.topImage.sd_setImage(with: URL.init(string: banners[topIndex].bgImg!), completed: nil)
                    self.bottomImage.sd_setImage(with: URL.init(string: banners[bottomIndex].bgImg!), completed: nil)
                    UIView.animate(withDuration: 0.5, animations: {
                        self.leftView.setRadius(radius: (mainW * CGFloat(self.draggingIndex) - curretContentOffset) * 2, direction: .right)
                        self.rightView.setRadius(radius: 0, direction: .left)
                    })
                    
                }else{
                     //向右
                    let cell1 = banner.cellForItem(at: IndexPath.init(row: self.draggingIndex, section: 0))
                    let cell2 = banner.cellForItem(at: IndexPath.init(row: self.draggingIndex + 1 >= totalItemCount ? totalItemCount/2 : draggingIndex + 1, section: 0))
                    
                    UIView.animate(withDuration: 0.1) {
                        cell1?.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
                        cell2?.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)
                    }
                    
                    let topIndex = itemIndex + 1 > self.banners.count - 1 ? 0 : itemIndex + 1
                    let bottomIndex = itemIndex
                    self.topImage.sd_setImage(with: URL.init(string: banners[topIndex].bgImg!), completed: nil)
                    self.bottomImage.sd_setImage(with: URL.init(string: banners[bottomIndex].bgImg!), completed: nil)
                    UIView.animate(withDuration: 0.5, animations: {
                        self.leftView.setRadius(radius: 0, direction: .right)
                        self.rightView.setRadius(radius: (mainW * CGFloat(self.draggingIndex) - curretContentOffset) * 2, direction: .left)
                    })
                }
            }
    
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
            //拖动结束后
            lastContentOffset = scrollView.contentOffset.x
            self.autoScrollIndex = self.currentIndex()
            
            let cell1 = banner.cellForItem(at: IndexPath.init(row: self.autoScrollIndex - 1 < 0 ? totalItemCount :  self.autoScrollIndex - 1 , section: 0))
            let cell2 = banner.cellForItem(at: IndexPath.init(row: self.autoScrollIndex , section: 0))
            let cell3 = banner.cellForItem(at: IndexPath.init(row: self.autoScrollIndex + 1 > totalItemCount ? totalItemCount/2 : 0, section: 0))
            
            UIView.animate(withDuration: 0.2) {
                cell1?.transform = CGAffineTransform(scaleX: 1, y: 1)
                cell2?.transform = CGAffineTransform(scaleX: 1, y: 1)
                cell3?.transform = CGAffineTransform(scaleX: 1, y: 1)
            }
        }
        
    
    

    2、背景动画

    思路:
    在view底层有两个imageView  在最上层的view加个MaskView(遮罩)MaskView 上分别添加两个view即leftView以及当banner滚动时 改变左右的圆的半径 实现动画效果
    
    UIView.animate(withDuration: 0.5, animations: {
                        self.leftView.setRadius(radius: (curretContentOffset - mainW * CGFloat(itemIndex)) * 2, direction: .right)
                        self.rightView.setRadius(radius: 0, direction: .left)
                    })
    
    UIView.animate(withDuration: 0.5, animations: {
                        self.leftView.setRadius(radius: 0, direction: .right)
                        self.rightView.setRadius(radius: (curretContentOffset - mainW * CGFloat(self.autoScrollIndex)) * 2, direction: .left)
                    })
    
    
    import UIKit
    
    enum MDBannerSrollDirection {
        case unknow
        case left
        case right
    }
    
    class MDMaskView: UIView {
    
        // Only override draw() if you perform custom drawing.
        // An empty implementation adversely affects performance during animation.
        
        var maskRadius:CGFloat = 0
        var direction:MDBannerSrollDirection = .unknow
        func setRadius(radius:CGFloat,direction:MDBannerSrollDirection){
            self.maskRadius = radius
            self.direction = direction
            if self.direction != .unknow{
                self.setNeedsDisplay()
            }
            
        }
        
        override func draw(_ rect: CGRect) {
            self.backgroundColor = .clear
            if direction != .unknow{
                let ctx = UIGraphicsGetCurrentContext()
                if direction == .left{
                    ctx?.addArc(center: CGPoint(x: self.center.x + rect.width/2, y: self.center.y), radius: maskRadius, startAngle: 0, endAngle: .pi * 2, clockwise: false)
                }else{
                    ctx?.addArc(center: CGPoint(x: self.center.x - rect.width/2, y: self.center.y), radius: maskRadius, startAngle: 0, endAngle: .pi * 2, clockwise: false)
                }
                ctx?.setFillColor(UIColor.white.cgColor)
                ctx?.fillPath()
            }
        }
    
    }
    
    

    github地址 https://github.com/daimengxiaozhi/MDShockBannerView 给个Star吧!
    2018.4.27 新增OC版本 2018.5.3 新增Android版本
    注:初步尝试可能会有bug,欢迎大家提出建议。

    附安卓使用代码:

      classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1'
            classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
    
    
    
     mBannerList = result.data;
    mBOneBanner.setImages(mBannerList)
                            .setImageLoader(new GlideImageLoader()).start();
     @Override
        public void onStart() {
            super.onStart();
            mBOneBanner.stopAutoPlay();
        }
    
        @Override
        public void onStop() {
            super.onStop();
            //结束轮播
            mBOneBanner.stopAutoPlay();
        }
    @Override
        public void OnBannerClick(int position) {
          //点击事件
        }
    

    相关文章

      网友评论

      • 744eaedce85b:这个写的挺不错的,不过有Bug,底部图会闪的厉害。偶现(出现了好几次了)。能不能看一下,谢谢。
        z小志:@这个名字可以啊 好的
        744eaedce85b:@z小志 客户反应的,我这就出现了几次,下次在出现的时候,给你录下来,其它的都挺好。
        z小志:具体怎么闪的??
      • e8d19cc9c82f:我想问一下Android版本 还更新吗?Android版本感觉很多bug
        z小志:@tokiii 给你点个赞
        卷卷更健康:看我刚写的,心累~~~ https://www.jianshu.com/p/2475a15ee5d2
      • eec52a6bd072:大佬安卓有更新吗...效果没ios好呀
        _伤也快乐:乱改了一堆!勉强能用!不过内存占用太大
        eec52a6bd072:@z小志 😩😩😩😩
        z小志:@我的薇恩会冲锋 没有哎:disappointed_relieved:
      • 妖猪:缺少文件吧
      • 卷卷更健康:大佬的iOS写的不错,但是Android 的真是没法用,效果也是差强人意,感觉不是一个水准。。。。
        z小志:@保持专注 :joy:我是iOS 安卓是同事写的。可能只是个初级版。思路有 自己写个也可以。
      • 鱼__鱼:大佬确认这是 转转的源码吗?android 的
        z小志:@鱼__鱼 公司做的。可能代码不全吧。我给同事要的人安卓的
        鱼__鱼:@z小志 你们公司做的?还是咋的,运行起来的demo动效有问题额,不知道你那边的源码是在哪里获取的
        z小志:@鱼__鱼 不确定啊。我感觉用的都说有问题。:sweat::sweat:
      • 82b01b4d781f:大佬,android版运行后 JNI ERROR (app bug): local reference table overflow (max=512) ,怎么办呀
        82b01b4d781f:@z小志 这个配置本来就有了,我在布局文件中引用的Banner文件,啥都不做就会报那个错误。
        z小志:添加还需要这个 classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1'
        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
        z小志:@GK1234 这个我也看不懂 :sweat:
      • jiangbin1992:请问Android链接在何处,这边ios采取这个 Android的一样啊 请问在哪
        z小志:@jiangbin1992 额。不是有个安卓文件么。直接调用不行么
        jiangbin1992:@z小志 我看了 没有跟iOS的仿转转banner一样的啊
        z小志:@jiangbin1992 在github
      • 大树12999:厉害了
      • 我要的飞翔_ffa6:安卓版的源码在哪啊,给个链接好伐
      • selice:有么有oc版本啊,大佬。
        selice:@z小志 :cry:感谢,我还在学swift 呢
        z小志:github 跟新了 OC 版本
        z小志:@selice 这个没有。你可以根据swift 仿写一个。
      • ZSLiao:大佬好!!
        z小志:@我要的飞翔_ffa6 我给你要一下
        我要的飞翔_ffa6:安卓版的在哪啊,博主给个链接好伐
        z小志:大佬你好,约否??

      本文标题:仿转转首页Banner图

      本文链接:https://www.haomeiwen.com/subject/jpxllftx.html