美文网首页编程iOS-swift
天猫首页的视差Banner

天猫首页的视差Banner

作者: 尛破孩波波 | 来源:发表于2017-10-11 21:18 被阅读239次

    简介

    在天猫消费升级、品质升级的大背景下,一个交互体验优秀的APP变得尤为重要。而首页的首焦Banner更应该精雕细琢,因此我们挖掘了体验上的小创新,希望能给用户眼前一亮的体验小惊喜。我们实现了多层基于不同位移系数,接收重力感应及手势滑动的banner,从而达到视差的效果,让整个产品更生动富有细节。

    img

    绘制视图

    Banner上每一个Item其实是相互独立的,而想做到视差,必须将有不同相对速度的视图放在不同的层,将相对静止的视图放在同一层。

    数据结构:

    {
      "data": [
        {
          "imgUrl": "https://img.alicdn.com/tps/i4/TB1DdQ7RVXXXXa.XFXXwu0bFXXX.png",
          "gapSpeed": "1.2",
          "intensity": "10"
        },
        {
          "imgUrl": "https://img.alicdn.com/tps/i4/TB1fM8uSXXXXXauXXXXwu0bFXXX.png",
          "gapSpeed": "1.4",
          "intensity": "20"
        }
      ],
        "imgUrl": "//img.alicdn.com/imgextra/i1/36/TB22s9LuiC9MuFjSZFoXXbUzFXa_!!36-2-luban.png",
      "bgImgUrl": "https://img.alicdn.com/tps/i4/TB1fNIERVXXXXcUapXXSutbFXXX.jpg"
    }
    
    字段 二级字段 作用
    imgUrl - 默认静态图
    bgImgUrl - 背景图片
    data - 用户存放item上每一个视差对象
    - imgUrl 视差图片
    - gapSpeed 滚动视差的相对速度
    - intensity 重力视差的最大位移

    视图结构

    img

    根据data中object数目,创建多个视图,根据object的下标确定视图的先后位置。如上图所示:根据gapSpeed来确定视图的长度,创建出‘1.2X’和‘1.6X’两个视图,并且将图片居中展示。

    加载过程

    初始化后,我们先根据imgUrl字段在1X的视图中加载默认静态图片,然后等data中的资源全部下载完成之后,将1X中得图片替换成bgImgUrl对应的图片,并且展示1.2X和1.6X两个视图。此时,用户对图片的变化并没有感知,但当banner滚动或转动手机时,用户会发现banner已经拥有3D视差组件了哦。

    滚动视差

    正如上图所示,我们可以将视差组件“大牌热促”分成三个过程:“进入屏幕前”、“在屏幕中”、“离开屏幕后”

    进入屏幕前

    进入屏幕前,所有的视图居左对齐,以达到最大的靠右视差。

    在屏幕中

    当banner从右往左滚动时,1.2X的视图将以banner滚动速度的0.1倍的速度在坑位内滚动,同理,1.6X的视图以banner滚动速度的0.3倍的速度在坑位内滚动,当banner正好将此卡片滚到屏幕正中间时,上面的所有视图与1X视图居中,所有的Image都重叠在一起,协作展示完整的Item内容.

    离开屏幕后

    当banner将Item从屏幕左侧滑出之后,所有的视图正好向右对齐,此时达到最大的靠左视差。

    实现代码

    理解完了原理,我们就直接上代码吧,由于每一个Item无法获取Banner的scrollview.delegate,所以,我们用TangramBug,将此消息传递给每一个Item,并在这个方法中,完成以上操作:

    -(void)didScrollView:(TangramContext *)context
    {
        UIScrollView *scrollView = [context.event.params objectForKeyCheck:@"scrollView"];
        CGPoint point = [self convertPoint:CGPointZero toView:scrollView];
        CGFloat offsetX = point.x - scrollView.contentOffset.x - scrollView.width + (scrollView.width - self.width) / 2;
        if (self.data.count > 0)
        {
            CGFloat gapSpeed = [[self.data dictionaryAtIndex:0] floatForKey:@"gapSpeed" defaultValue:1.0];
            self.gapView1.left = offsetX * (gapSpeed- 1)/ 2;
        }
        if (self.data.count > 1)
        {
            CGFloat gapSpeed = [[self.data dictionaryAtIndex:1] floatForKey:@"gapSpeed" defaultValue:1.0];
            self.gapView2.left = offsetX * (gapSpeed- 1)/ 2;
        }
        if (self.data.count > 2)
        {
            CGFloat gapSpeed = [[self.data dictionaryAtIndex:2] floatForKey:@"gapSpeed" defaultValue:1.0];
            self.gapView3.left = offsetX * (gapSpeed- 1)/ 2;
        }
    }
    

    重力视差

    说到重力,肯定会谈起ios的陀螺仪,相关CMDeviceMotion的知识我就不在重复讲解,相关介绍可以参考这篇文档:http://www.tuicool.com/articles/2YZRvq。 为了让猫客内的UIView以后更轻松的接入重力感应,所以我把其能力作为了UIView的category实现。

    添加属性名称 类型 作用说明
    parallaxIntensity CGFloat 重力感应最大位移距离,0为无视觉差,正数为和设备方向一致,负数为和设备方向相反
    parallaxDirection NSInteger 0:所有方向;1:只能在X轴上移动;2:只能在y轴上移动

    根据之前的json中的intensity字段,我们把1.2X的视图的parallaxIntensity设为10,同理把1.6X视图的parallaxIntensity设为20。

    开启重力视差

    parallaxIntensity字段不为0时,我就会调用方法-(void)startDeviceMotionUpdatesToQueue:withHandler:,并且将deviceMotionUpdateInterval属性设置为一个较高的刷新频率,目的是为了动画流畅,响应及时。
    特别需要注意的是,当手机从正面转到反面时,roll会有一个临界值的变化需要经过特殊处理,否则会发现对象会突然跳到另一边,因此,我们需要做如下操作:

    if (tmMuiCurrentAttitude.roll > -M_PI_2 && tmMuiCurrentAttitude.roll < M_PI_2) 
    {
            currentPoint = CGPointMake(tmMuiCurrentAttitude.roll, tmMuiCurrentAttitude.pitch);
    }
    else
    {
        if (tmMuiCurrentAttitude.roll > M_PI_2)
        {
            currentPoint = CGPointMake(M_PI - tmMuiCurrentAttitude.roll,tmMuiCurrentAttitude.pitch);
        }
        else
        {
            currentPoint = CGPointMake(-M_PI - tmMuiCurrentAttitude.roll, tmMuiCurrentAttitude.pitch);
        }
    }
    

    之后我们得到了一个变换后的roll和pitch,将其和初始的数值做对比之后,我们就得到了一个变化量,将这个变化量换算成与最大值的百分比,再根据parallaxIntensity换算出一个变化的point,然后我们根据parallaxDirection对其transform进行设置,根据parallaxDirection来确定只设置某一个方向还是全方向都设置。

    关闭重力视差

    parallaxIntensity字段为0时,我们就调用-(void)stopDeviceMotionUpdates方法,停止对陀螺仪的监听,并且将视图位置恢复原状。

    结束语

    就这样,我们一步步地打造了一个拥有滚动视差、重力视差的banner组件。虽然这只是一个极小的细节,但是交互的升级,必将带给用户新鲜的体验。试问:一个lowlow的app怎么可能让用户升级呢?首页作为天猫最重要的页面,必须精雕细琢每一个细节!

    相关文章

      网友评论

      本文标题:天猫首页的视差Banner

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