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

先看看原版的效果

再看看模仿的效果



分析

控件结构分析

由于*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执行JS -- PyExecJS库

    pip install PyExecJS 查看执行JS的环境 print(execjs.get().name) 返回值:JScript windows 默认执行JS的环境 返回值:Node.js (V ...

  2. redis簡單命令

  3. A. Coffee Break(思维题,类似于邻接表的head数组用法)

    题:https://codeforces.com/gym/101911/problem/A 题意:每天工作m分钟,每次喝coffee得间隔d分钟,然后给出n个数,每个数表示想在一天中的a[i]的时刻喝 ...

  4. 使用 Wintersmith + Serverless Framework 快速创建个人站点

    首先我们来介绍下,Wintersmith 是一个简单而灵活的静态站点生成器.采用 markdown 构建,这个是我们的基础条件. Serverless Framework:在 GitHub 上有三万颗 ...

  5. open 管道用法|Getopt::Long

    #!/usr/bin/perl use strict; use warnings; use Getopt::Long; my ($number,$in,$out); GetOptions( " ...

  6. JS如何按时间粒度获取date的时间差

    获取date类型 var type = _xAxis[0].split(/-|:|\s/).length; 按时间粒度获取date的时间差 function getDateDiffByType(new ...

  7. Excel-DNA自定义函数的参数智能提示功能:ExcelDna.IntelliSense1.1.0.rar

    解压缩后,可以看到如下3个文件. ExcelDna.IntelliSense.xll 以及 ExcelDna.IntelliSense64.xll 是两个函数参数智能提示加载项,分别用于32和64位E ...

  8. [LC] 198. House Robber

    You are a professional robber planning to rob houses along a street. Each house has a certain amount ...

  9. LeetCode No.73,74,75

    No.73 SetZeroes 矩阵置零 题目 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 输入: [   [1,1,1],   [ ...

  10. Node.js //TODO

    目录 技术背景 开发环境 学习过程 参考资料 结束语 技术背景 开发环境 学习过程 参考资料 结束语