Android自定义LinearLayout实现淘宝详情页

1.简单说明

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

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

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

2.实现思路

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

 @Override
 protected 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

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 /**
  * 显示调用第二个自孩子的测量方法,不然尺寸有可能为0
  */
 View child2 = getChildAt(1);
 if (child2 != null) {
  child2.measure(widthMeasureSpec, heightMeasureSpec);
 }
 }

在onFinishInflate中初始化两个页面

@Override
 protected 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() {
 @Override
 public void scrollToBottom(View view) {
  if(view == scrollView1){
  isToBotttom = true;
  }
 }

 @Override
 public void scrollToTop(View view) {
  if(view == scrollView2){
  isToTop = true;
  }
 }

 @Override
 public 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中。你的任务是获取并使用一个合适的速度,使滚动动画看起来更平滑。

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

需要重写的方法

@Override
 public 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滑动,实现弹性效果,简单实现请看这里简单的弹性实现代码

@Override
 public 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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现类似360,QQ管家那样的悬浮窗

    一.前言: 我手机从来不装这些东西,不过,有次看到同事的android手机上,有个QQ管家在桌面上浮着,同事拖动管家时,管家就变成一只鸟,桌面下方还有个弹弓,桌面顶部有只乌鸦,把管家也就是鸟拖动到弹弓那,然后,松手,鸟就飞出去.这个过程是动画过程,做的事,实际上是清楚内存. 二:原理: 其实,没什么原理,用到的就是WindowManager以及WindowManager.LayoutParams,对这个LayoutParams做文章,当设置为属性后,然后,创建一个View,将这个View添加到W

  • 安卓(android)仿电商app商品详情页按钮浮动效果

    1.效果图如下: 这效果用户体验还是很酷炫,今天我们就来讲解如何实现这个效果. 2.分析 为了方便理解,作图分析 如图所示,整个页面分为四个部分: 1.悬浮内容,floatView 2.顶部内容,headView 3.中间内容,与悬浮内容相同,middleView 4.商品详情展示页面,detailView 因为页面内容高度会超出屏幕,所以用Scrollview实现滚动,悬浮view与scrollview同级,都在一个帧布局或者相对布局中. 当y方向的滚动距离小于中间的内容middleView到

  • Android仿淘宝商品拖动查看详情及标题栏渐变功能

    绪论 最近一直比较忙,也没抽出时间来写博客,也不得不说是自己犯了懒癌,人要是一懒就什么事都不想做了,如果不能坚持下来的话,那么估计就废了,��.最近自己攒了好多东西,接下来的时间我会慢慢都分享出来的.好了废话不多说了,下面我们开始正题: 今天要分享的是淘宝的详情页,之前在淘宝上买东西的时候看到淘宝的详情页效果比较不错,所以今天就来仿一下它的效果吧,可能没有淘宝的好,希望见谅啊. 先上效果图: 这是淘宝的: 我自己做的: 怎么样效果还差不多吧?GIF图效果看的不太清楚,见谅. 下面我们来看看怎么实

  • Android TabLayout实现京东详情效果

    Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的Android Design Support Library,在这个support库里面,Google给我们提供了更加规范的MD设计风格的控件.最重要的是,Android Design Support Library的兼容性更广,直接可以向下兼容到Android 2.2. 这两天需要做一个仿京东详情的页面,上面的Tab切换,以前都是自己写Viewpager+fragment

  • Android实现仿360桌面悬浮清理内存

    今天闲来无事写了一个清内存的小东西,类似360,在桌面上悬浮,点击后清除后台无用程序,清除后台程序是通过调用ActivityManger.killBackgroundProcesses的方式来进行的,这样的方式有个不好的地方,就是重要性级别设置的高的应用杀不掉.关键代码如下所示 ActivityManager mActivityManager = MyManager.getActivityManager(mContext); List<ActivityManager.RunningAppProc

  • Android如何跳转到应用商店的APP详情页面

    需求:从App内部点击按钮或链接,跳转到应用商店的某个APP的详情页面. 让用户 下载 或 评论. 实现: /** * 启动到应用商店app详情界面 * * @param appPkg 目标App的包名 * @param marketPkg 应用商店包名 ,如果为""则由系统弹出应用商店列表供用户选择,否则调转到目标市场的应用详情界面,某些应用商店可能会失败 */ public void launchAppDetail(String appPkg, String marketPkg)

  • Android 仿淘宝、京东商品详情页向上拖动查看图文详情控件DEMO详解

    一.淘宝商品详情页效果 我们的效果 二.实现思路 使用两个scrollView,两个scrollView 竖直排列,通过自定义viewGroup来控制两个scrollView的竖直排列,以及滑动事件的处理.如下图 三.具体实现 1.继承viewGroup自定义布局View 重写onMeasure()和onLayout方法,在onLayout方法中完成对两个子ScrollView的竖直排列布局,代码如下: 布局文件: <RelativeLayout xmlns:android="http:/

  • Android通过自定义控件实现360软件详情页效果

    一.概述 最近有不少朋友私聊问应用宝.360软件助手之类的软件详情页怎么做,刚好,最近有时间就模仿360软件助手详情页给大家做个Demo,供大家参考.嗯,关于实现呢,我写了两种方式: 1.ScrollView内嵌软件介绍+ViewPager+ViewPager中是ScrollView,这种方式呢,纯原生,没有涉及到自定义控件,但是这样嵌套呢,涉及到测量以及事件的冲突处理,大家可以自己尝试去做一下,想像起来蛮容易的,做起来其实还是挺费劲的,代码我会给出,核心代码不多,大家自行参考.本文将重点分析第

  • Android应用自动跳转到应用市场详情页面的方法

    前言 众所周知在Android应用开发过程中,可能会有需求,比如:推广时跳转到应用市场下载应用,跳转到应用市场给自己的应用打分,跳转到应用市场更新自己的应用. 那如何跳转到应用市场呢? 可能跳转的方法大家都是知道的,方法如下: public static void goToMarket(Context context, String packageName) { Uri uri = Uri.parse("market://details?id=" + packageName); Int

  • Android模仿知乎的回答详情页的动画效果

    废话不多说,咱们第一篇文章就是模仿"知乎"的回答详情页的动画效果,先上个原版的效果图,咱们就是要做出这个效果 在实现之前,我们先根据上面的动画效果,研究下需求,因为gif帧数有限,所以不是很连贯,推荐你直接下载一个知乎,找到这个界面自己玩玩 ☞当文章往上移动到一定位置之后,最上面的标题栏Bar和问题布局Title是会隐藏的,回答者Author布局不会隐藏 ☞当文章往下移动移动到一定位置之后,原先隐藏的标题栏Bar和问题布局Title会下降显示 ☞当文章往上移动的时候,下部隐藏的Tool

随机推荐