1.简单说明

  1. 淘宝详情页就不用我一一介绍了,昨天逛淘宝看到这个效果时,让我想起了去年刚学习Android只会使用现成的时候,当时在网上找了一个这种效果的使用了,并不懂怎么实现的。现在就看到一种效果就想自己实现一下,我想这就是刚接触某个知识时的好奇心吧

  2. 说走咱就走啊,本文只是介绍一种实现思路,网上也已经有了很多种实现方式,有问题请指正

  3. 效果图(我有很用心的找美女图的)

2.实现思路

  1. 继承LinearLayout,设置方向为垂直
  2. 控件中有两个ScrollView,至于为什么要使用ScrollView,主要是因为内容超过一页时省去自己处理滑动
  3. 关键是事件分发处理。监听两个ScrollView的滑动事件,当第一页滑动到底部时,再向上拖动时,拦截事件,判断距离,超过设定值时,滑动到第二页,否则回弹;同理,当第二页滑动到顶部时,再向下拖动时,拦截事件,判断距离,超过设定值时,滑动到第一页,否则回弹(还有很多细节需要结合代码讲解)
  4. 关于回弹和滑动换页使用的是Scroller,对于Scroller的使用,本文不做过多解释

3.实现

3.1重写ScrollView

根据实现思路,我们需要监听ScrollView是否滑动到顶部和底部,但是ScrollView的setOnScrollChangeListener()方法在api23才添加。主要是重写ScrollViewonScrollChanged(int l, int t, int oldl, int oldt)方法。

l:当前水平方向滚动值,和getScrollX()相等
t:当前竖直方向滚动值,和getScrollY()相等
oldl:上一次水平滚动值
oldt:上一次竖直滚动值

  • 监听接口:
    public interface OnScrollEndListener {void scrollToBottom(View view);void scrollToTop(View view);void scrollToMiddle(View view);}
  • onScrollChanged方法
 @Overrideprotected void onScrollChanged(int l, int t, int oldl, int oldt) {super.onScrollChanged(l, t, oldl, oldt);if(t == 0){if (mOnScrollBottomListener != null) {mOnScrollBottomListener.scrollToTop(this);}} else if(t + getMeasuredHeight() >=  getChildAt(0).getMeasuredHeight()){if (mOnScrollBottomListener != null) {mOnScrollBottomListener.scrollToBottom(this);}} else {if (mOnScrollBottomListener != null) {mOnScrollBottomListener.scrollToMiddle(this);}}}

3.2重写onMeasure方法、page的获取与设置

  • 显示调用第二个自孩子的测量方法,不然尺寸有可能为0
    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);/*** 显示调用第二个自孩子的测量方法,不然尺寸有可能为0*/View child2 = getChildAt(1);if (child2 != null) {child2.measure(widthMeasureSpec, heightMeasureSpec);}}
  • 在onFinishInflate中初始化两个页面
@Overrideprotected void onFinishInflate() {super.onFinishInflate();if(getChildCount() == 2){View child1 = getChildAt(0);if (child1 instanceof ScrollEndScrollView){scrollView1 = (ScrollEndScrollView) child1;}View child2 = getChildAt(1);if(child2 instanceof ScrollEndScrollView){scrollView2 = (ScrollEndScrollView) child2;}}initEvent();}
  • 为两个页面设置滑动监听
private ScrollEndScrollView.OnScrollEndListener scrollEndListener = new ScrollEndScrollView.OnScrollEndListener() {@Overridepublic void scrollToBottom(View view) {if(view == scrollView1){isToBotttom = true;}}@Overridepublic void scrollToTop(View view) {if(view == scrollView2){isToTop = true;}}@Overridepublic void scrollToMiddle(View view) {if(view == scrollView1){isToBotttom = false;}if(view == scrollView2){isToTop = false;}}};

3.3Scroller使用的几步

Scroller的英文解释是:
This class encapsulates scrolling. You can use scrollers (Scroller or OverScroller) to collect the data you need to produce a scrolling animation—for example, in response to a fling gesture. Scrollers track scroll offsets for you over time, but they don’t automatically apply those positions to your view. It’s your responsibility to get and apply new coordinates at a rate that will make the scrolling animation look smooth.

此类封装滚动。您可以使用滚动条(滚轮或OverScroller)收集你需要制作一个滚动的动画,例如,响应一扔手势的数据。滚动条为您跟踪滚动偏移量随着时间的推移,但他们不会自动将新的位置设置到View中。你的任务是获取并使用一个合适的速度,使滚动动画看起来更平滑。

简而言之,有关滑动的你都可以使用这个实现。

  • 需要重写的方法
@Overridepublic void computeScroll() {super.computeScroll();//先判断mScroller滚动是否完成if (mScroller.computeScrollOffset()) {//这里调用View的scrollTo()完成实际的滚动scrollTo(mScroller.getCurrX(), mScroller.getCurrY());//必须调用该方法,否则不一定能看到滚动效果postInvalidate();}}
  • 辅助方法
    //调用此方法设置滚动的相对偏移public void smoothScrollBy(int dx, int dy) {//设置mScroller的滚动偏移量mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, Math.max(300, Math.abs(dy)));invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果}
//调用此方法滚动到目标位置public void smoothScrollTo(int fx, int fy) {int dx = fx - mScroller.getFinalX();int dy = fy - mScroller.getFinalY();smoothScrollBy(dx, dy);}

3.4事件分发

最关键的部分,逻辑稍复杂,细节处理较多。这里重写dispatchTouchEvent。

显示第一页时

  • 未滑动到底部,事件由scrollView1自己处理
  • 滑动到底部时,如果继续向上拖动,拦截事件,父控件处理滑动;继续向下拖动时,如果父控件(即该控件)当前滚动最后位置(mScroller.getFinalY())不为0, 如果父控件继续滚动不会出现负值时(出现负值时会导致头部空白,因为这时是父控件控制,scrollView1不可滑动),不拦截事件,父控件处理滑动,否则,强制滑动到0位置,并把事件下发给子控件

显示第二页时

  • 未滑动到最顶部时,事件由scrollView2自己处理
  • 滑动到顶部时,如果继续向下拖动,拦截事件,父控件处理滑动;继续向上拖动时,如果父控件当前滚动位置小于第一页高度,拦截事件,父控件处理滑动,否则,滑动到第二页起始位置,并把事件下发给子控件

  • ACTION_MOVE中进行事件分发,ACTION_UP中进行切换页面、回弹
  • 关于使用scroller滑动,实现弹性效果,简单实现请看这里简单的弹性实现代码

@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {int action = ev.getAction();int yPosition = (int) ev.getY();switch (action) {case MotionEvent.ACTION_DOWN:mScroller.abortAnimation();mLastY = yPosition;mMoveY = 0;break;case MotionEvent.ACTION_MOVE:mMoveY = (mLastY - yPosition);mLastY = yPosition;if(isToBotttom){if(mMoveY > 0){//向上smoothScrollBy(0, mMoveY);return true;} else {//向下if(mScroller.getFinalY() != 0){//这是出于第一页和第二页显示连接处if(getScrollY() + mMoveY > 0){smoothScrollBy(0, mMoveY);return true;} else{smoothScrollTo(0, 0);return super.dispatchTouchEvent(ev);}}}}else if(isToTop){if(mMoveY < 0){//向下smoothScrollBy(0, mMoveY);return true;} else {//向上if(mScroller.getFinalY() < scrollView1.getHeight()){//这是出于第一页和第二页显示连接处smoothScrollBy(0, mMoveY);return true;} else {smoothScrollTo(0, scrollView1.getHeight());return super.dispatchTouchEvent(ev);}}}//处理快速滑动时两页覆盖问题if(pageIndex == 0){smoothScrollTo(0, 0);} else if(pageIndex == 1){smoothScrollTo(0, scrollView1.getHeight());}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:if(isToBotttom){if(Math.abs(getScrollY()) > TO_NEXT_PAGE_HEIGHT){//移动到第二页pageIndex = 1;smoothScrollTo(0, scrollView1.getHeight());isToBotttom = false;isToTop = true;} else {//回弹smoothScrollBy(0, -mScroller.getFinalY());}} else if(isToTop){if(scrollView1.getHeight() - getScrollY() > TO_NEXT_PAGE_HEIGHT){//移动到第一页pageIndex = 0;smoothScrollTo(0, 0);isToBotttom = true;isToTop = false;} else {//回弹smoothScrollTo(0, scrollView1.getHeight());}}break;default:break;}return super.dispatchTouchEvent(ev);}

4.总结

实现该控件,需要掌握的知识点主要是自定义控件的基本步骤、Scroller的基本使用和事件分发,当然这里最关键的处理还是事件分发。开头也说了,虽然这个有很多人实现过了,但还是想用自己的方式实现一遍。大笑三声,哈哈哈,又实现一个自定义控件…博主还在自定义控件学习阶段,请谨慎使用该控件到项目中。

5.下载

https://github.com/LineChen/TwoPageLayout

自定义LinearLayout实现淘宝详情页相关推荐

  1. 自定义View之仿淘宝详情页

    自定义View之仿淘宝详情页 转载请标明出处: http://blog.csdn.net/lisdye2/article/details/52353071 本文出自:[Alex_MaHao的博客] 项 ...

  2. 淘宝详情页分发推荐算法总结:用户即时兴趣强化

    本文介绍淘宝详情页全网分发场景的机制. 商品详情页是手淘内流量最大的模块之一,它加载了数十亿级商品的详细信息,是用户整个决策过程必不可少的一环.这个区块不仅要承接用户对当前商品充分感知的诉求,同时也要 ...

  3. 仿淘宝详情页 直接上代码

    仿淘宝详情页 直接上代码 package com.example.liketitledemo;import android.content.Context; import android.graphi ...

  4. UNIAPP----仿淘宝详情页滚动

    淘宝详情页,滚动时,上面的选项卡也随之改变,本代码为测试版,我自己测可用,全部复制可运行参考. 核心思想:监听屏幕滚动距离,动态修改上面选中样式,也就是上面的字体会被选中. 点击上面字体获取下标,跳转 ...

  5. 弘辽科技:优秀的淘宝详情页应包含哪些内容?

    原标题<弘辽科技:优秀的淘宝详情页应包含哪些内容?> 淘宝详情页是影响顾客是否愿意下单的重要因素之一.宝贝的详情页不但会影响商品的转化,而且也反映出客户浏览商品的时长,对权重排名以及流量的 ...

  6. 制作淘宝详情页时要注意哪些细节?

    对于淘宝开店的商家们来说,都知道商品的标题.主图.价格以及详情页都是影响着顾客是否下单的重要因素.那么怎么制作淘宝详情页才能够提升转化呢?接下来小编就给大家详细的讲一讲制作详情页细节有哪些. 1.制作 ...

  7. 用原生js实现淘宝详情页图片放大镜效果

    这个功能是我在模仿淘宝详情页的时候做出来的,最初版本对于非1:1比例的图片没有做处理,后续对程序进行了完善和逻辑上修改,形成了当前的程序. 废话不多说,直接进入正题了,先上个效果图 先放上这段功能的h ...

  8. Android模仿淘宝详情页界面

    话不多说-先上效果图: 图1中主要需要实现的效果: 1.轮播图 2.顶部导航栏的渐变 3.顶部导航栏随着滑动的位置选择对应的值以及点击滑动到对应位置 Android模仿淘宝详情页界面文件:url80. ...

  9. 足迹推荐位,淘宝足迹推荐位,旺旺打标足迹显示问题,详情页足迹推荐,淘宝详情页的下拉出现足迹,v兔电商

    淘宝的千人千面算法已经连带足迹推荐都开始个性化了.淘宝详情页的下拉出现足迹实现方法. 一.首先了解一下什么是足迹推荐位: 在最新版本手淘版本9.00.0之后的版本,点击到任意到任意的商品详情页中下拉会 ...

最新文章

  1. ViewStub 使用注意事项
  2. 打架斗殴烫头酗酒抽烟的小混混,逆袭保送中国科学院,后来怎么样了?
  3. 计算机共享用户名和密码是哪个文件夹,共享文件夹要输入用户名密码,微信密码在哪个文件夹...
  4. 高等数学上-赵立军-北京大学出版社-题解-练习5.8
  5. Gradle入门:创建二进制分发
  6. python合并数组输出重复项_python进行数组合并的方法
  7. 学好JAVA保终身_JAVA IO 学习
  8. 一文解读元学习研究进展
  9. sqlserver2012安装
  10. Mac Duet使用教程
  11. c语言消消乐字母游戏代码,基于pygame的小游戏———数字消消乐
  12. JS-修改图片颜色值
  13. Java网络编程 获取本地主机名称和地址
  14. 涉密计算机外送维修,涉密计算机及涉密介质维修
  15. K - Kinds of Fuwas----(2015 summer training #4 (Qualifying))
  16. COSCon'22@Beijing | 北京分会场等你赴约
  17. SurfaceControl.screenshot()用法和SurfaceControl.screenshot()使用后返回null的情况
  18. java刘备猜拳游戏类_基于java实现人机猜拳游戏
  19. 【滚动更新】Google退出中国后续报道之二
  20. WHUT第九周训练整理

热门文章

  1. 为让儿子从轮椅上站起来,工程师父亲打造外骨骼装置
  2. 深入研究HashMap
  3. 通过u盘启动计算机使用ghost安装系统步骤,u盘装系统ghost win7系统教程_电脑U盘启动怎样手动安装ghostwin7...
  4. 哪些应届生能年薪50W?
  5. LAMP编程之Linux-1
  6. 上海计算机二级报名无法选择,2020年二级计算机怎么报名上海
  7. StandardServer.await: create[8005]: java.net.BindException问题原因分析
  8. Android 客户端与服务器端进行数据交互(一、登录服务器端)
  9. 面试时谁都紧张,但我有诀窍!
  10. 设备安全——入侵检测IDS