逛豆瓣的时候看到了这样的控件,觉得挺有趣,遂模仿之

先看看原版的效果

再看看模仿的效果



分析

控件结构分析

由于*ScrollView只能有一个child view,所以整个child view的结构如图,这里我选择的是LinearLayout作为最外层的布局,content为展示的可滑动的内容,“更多”滑到最右边继续滑时出现的部分,先通过margin把“更多”隐藏

还有“更多”出现时的波纹效果,这个效果是通过贝塞尔曲线实现的,这里的实现比较简单,只取一个控制点,y坐标的数值为height的一半,x坐标随滑动距离变化

关键代码

控件的滑动效果由child view(下称wrapView)和content view(下称contentView)配合产生

  1. 当滑动到最左边并继续滑动的时候,wrapView的scrollX变化,产生第1个gif图效果
  2. 当滑动到最右边并继续滑动的时候,wrapView的scrollX先变化,当滑出到一定距离的时候,contentView的scrollX变化,产生第3个gif图效果
  3. 其他情况不处理滑动,交由HorizontalScrollView处理

详细参考以下代码

public boolean (MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = ev.getRawX();
break;
case MotionEvent.ACTION_MOVE:
float mDeltaX = (ev.getRawX() - mLastX);
mLastX = ev.getRawX();
mDeltaX = mDeltaX * RATIO;
if (mDeltaX > 0) {
if (!canScrollHorizontally(-1) || mWrapView.getScrollX() > 0) {
//contentView的scrollX > 0,contentView scroll,使scrollX变化
if (mContentView.getScrollX() > 0) {
mContentView.scrollBy((int) -mDeltaX, 0);
mMsg.setText(mStringDragged);
} else {
//wrapView的scrollX > 0,wrapView scroll,使scrollX变化
mWrapView.scrollBy((int) -mDeltaX, 0);
mMsg.setText(mStringDragging);
//贝塞尔曲线控制点变化
mControlPoint.x = (int) (mRect.right - mWrapView.getScrollX() * RIPPLE_RATIO);
mControlPoint.y = mRect.bottom / 2;
invalidate();
}
}
} else {
//不能右滑或者外层布局的scrollX < 0
if (!canScrollHorizontally(1) || mWrapView.getScrollX() < 0) {
if (!canScrollHorizontally(1)) {
getDrawingRect(mRect);
}
//wrapView的scrollX >= 产生"更多"动作的距离,contentView scroll,使scrollX变化
if (mWrapView.getScrollX() >= mOffset) {
mContentView.scrollBy((int) -mDeltaX, 0);
mMsg.setText(mStringDragged);
} else {
//wrapView的scrollX < 0,wrapView scroll,使scrollX变化
mWrapView.scrollBy((int) -mDeltaX, 0);
mMsg.setText(mStringDragging);
//贝塞尔曲线控制点变化
mControlPoint.x = (int) (mRect.right - mWrapView.getScrollX() * RIPPLE_RATIO);
mControlPoint.y = mRect.bottom / 2;
invalidate();
}
return true;
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
checkAction();
if (mWrapView.getScrollX() < 0) {
mScroller.startScroll(mWrapView.getScrollX(), 0, 0 - mWrapView.getScrollX(), 0,
(0 - mWrapView.getScrollX()) * 5);
} else if (mContentView.getScrollX() > 0) {
mScroller.startScroll(mContentView.getScrollX() + mWrapView.getScrollX(), 0,
0 - mContentView.getScrollX() - mWrapView.getScrollX(), 0,
(mContentView.getScrollX() + mWrapView.getScrollX()) * 6);
} else {
mScroller.startScroll(mWrapView.getScrollX(), 0, 0 - mWrapView.getScrollX(), 0,
mWrapView.getScrollX() * 5);
}
invalidate();
break;
}
return super.onTouchEvent(ev);
}

松手后复原的滑动效果使用Scroller完成,读者可参考相关文档和文章

源码和demo

github:horizontal-elasticity-scrollview

欢迎交流


仿豆瓣首页弹性滑动控件|Axlchen's blog的更多相关文章

  1. 基于Bootstrap仿淘宝分页控件实现

    .header { cursor: pointer } p { margin: 3px 6px } th { background: lightblue; width: 20% } table { t ...

  2. Android开发技巧——定制仿微信图片裁剪控件

    拍照--裁剪,或者是选择图片--裁剪,是我们设置头像或上传图片时经常需要的一组操作.上篇讲了Camera的使用,这篇讲一下我对图片裁剪的实现. 背景 下面的需求都来自产品. 裁剪图片要像微信那样,拖动 ...

  3. 仿IOS7日期选择控件(新)

    前面也写过好几篇仿IOS日期控件的文章,不过基本上都是基于Wheelview修改而来,大致实现了滑轮选择选项的效果,其实和ios7及以上的效果还是相差甚远,而本文中所展现的这个控件虽也是从网上而来(呵 ...

  4. Android-PickerView【仿iOS的PickerView控件,并封装了时间选择和选项选择这两种选择器】使用

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本文主要演示Android-PickerView的选项选择器.时间选择器的简单运用.由于每一个版本略有不用,所以实际使用方式以git ...

  5. android 开发进阶 自定义控件-仿ios自动清除控件

    先上图: 开发中经常需要自定义view控件或者组合控件,某些控件可能需要一些额外的配置.比如自定义一个标题栏,你可能需要根据不同尺寸的手机定制不同长度的标题栏,或者更常见的你需要配置标题栏的背景,这时 ...

  6. 【Qt】仿QQ表情选择控件

         表情选择控件在聊天应用中常常要用到,做起来尽管不复杂可是非常繁琐.特别是有些图标须要按顺序排列.每次重做必定是非常费时.所以我将聊天表情选择控件封装成一个独立的类QFaceSelectWid ...

  7. JCameraView 仿微信拍照Android控件(点击拍照,长按录小视频)

    JCameraView 控件介绍 这是一个模仿微信拍照的Android开源控件,主要的功能有如下: 点击拍照. 前后摄像头的切换. 长按录视频(视频长度为10秒内). 长按录视频的时候,手指上滑可以放 ...

  8. qml: 自定义按钮-- 仿QML自带控件;

    import QtQuick 2.0 Rectangle { id: btn; width:; height:; radius:; border.color: "#A3A3A3"; ...

  9. jquery仿jquery mobile的select控件效果

    不说废话.直接上代码 //仿jQuery mobile Select控件 //使用方法box为容器id,_id指控件id,selectvalue为选中值,Value为当前值 function Sele ...

随机推荐

  1. Python remove()和del语句 区别和辨析 列表删除操作

    del语句可以删除列表中下标处的值,表中被删除值后后面的所有值将向前移动一个下标 spam = ['A','B','C','D','E'] del spam[2] spam 打印显示:['A', 'B ...

  2. Python基础学习三

    Python基础学习三 1.列表与元组 len()函数:可以获取列表的元素个数. append()函数:用于在列表的最后添加元素. sort()函数:用于排序元素 insert()函数:用于在指定位置 ...

  3. LeetCode——735.行星碰撞

    给定一个整数数组 asteroids,表示在同一行的行星. 对于数组中的每一个元素,其绝对值表示行星的大小,正负表示行星的移动方向(正表示向右移动,负表示向左移动).每一颗行星以相同的速度移动. 找出 ...

  4. nips2014下载

    nips2014下载 wget http://papers.nips.cc/book/advances-in-neural-information-processing-systems-27-2014 ...

  5. Sex linkage

    I.8 Sex linkage 单倍体:性别决定基因(S\s)和与性别决定基因连锁的等位基因(A\a)存在于同一套遗传物质上,其配子结合和减数分裂图示如下: 如果性别是由染色体区域决定的,自然选择会避 ...

  6. windows10+apache2.4+python3.6部署Django2.2.4项目

    刚从家回来,老师让写专利,就开始准备写,初稿交给老师后,把我说了一顿,我就想着回去改呀,然后...老师找到了我,说是食品院那急需一个展示数据的平台,然我尽快干出来,我也是菜鸟啊,就没单独干过呀,即使是 ...

  7. springboot多数据源+jta事务管理配置

    1.创建一个maven项目,导入相关配置: <?xml version="1.0" encoding="UTF-8"?> <project x ...

  8. SVN服务器的搭建(二)

    上一篇介绍了VisualSVN Server和TortoiseSVN的下载,安装,汉化.这篇介绍一下如何使用VisualSVN Server建立版本库,以及TortoiseSVN的使用. 首先打开Vi ...

  9. BaseAdapter教程(2) BaseAdapter的notifyDataSetChanged动态刷新

    遇到了这麽一个需求,ListView滑到最底,然后会自动在底部加入新的Cell,实现动态刷新. 1. 首先,为ListView加上setOnScrollListener. lvHomePostItem ...

  10. CorsConfig

    package org.linlinjava.litemall.core.config; import org.springframework.context.annotation.Bean; imp ...