天猫首页的视差Banner

简介

在天猫消费升级、品质升级的大背景下,一个交互体验优秀的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怎么可能让用户升级呢?首页作为天猫最重要的页面,必须精雕细琢每一个细节!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,700评论 22 664
  • 中国人一直以来很看中出身,虽然说“英雄莫问出处”,但一个好的出身,会让大多人羡慕不已。 古代讲究门当户对,小说里的...
    90后女秀才阅读 879评论 0 0
  • 现在的初期,遇到很多无法想象无法接受的事要去面对。但是此时的我自我觉得还是该坚持,你不去逼迫自己怎么能发现自己的优...
    六月寒山雨阅读 268评论 0 0
  • 五月 送给了我这一生 最好的礼物 被六月 不怀好意的风 侵入 吹散了七月的温暖 八月从此凋零 九月的愁苦 在十月倒...
    hshy阅读 328评论 0 1
  • 天塌地陷一窟窿 女娲熔采补苍穹 神通广大造真人 永垂不朽真英雄 2017年5月18日
    水墨悠然阅读 481评论 9 14