组件作用为类似ViewPager但直接插视图的横向滚动容器。

修改自:http://blog.csdn.net/yaoyeyzq/article/details/7571940

在该组件基础上修正了滚动速度,使其匹配ViewPager的滚动速度,以下为代码:

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller; /**
* @author
*/
public class ScrollLayout extends ViewGroup { private static final int MAX_SETTLE_DURATION = 600; // ms private Scroller mScroller;
private VelocityTracker mVelocityTracker; /**
* 当前的屏幕位置
*/
private int mCurScreen; /**
* 设置默认屏幕的属性,0表示第一个屏幕
*/
private int mDefaultScreen = 0; /**
* 标识滚动操作已结束
*/
private static final int TOUCH_STATE_REST = 0;
/**
* 标识正在执行滑动操作
*/
private static final int TOUCH_STATE_SCROLLING = 1; /**
* 标识滑动速率
*/
private static final int SNAP_VELOCITY = 600; /**
* 当前滑动状态
*/
private int mTouchState = TOUCH_STATE_REST; /**
* 在用户触发ontouch事件之前,我们认为用户能够使view滑动的距离(像素)
*/
private int mTouchSlop; /**
* 手指触碰屏幕的最后一次x坐标
*/
private float mLastMotionX; /**
* 手指触碰屏幕的最后一次y坐标
*/
@SuppressWarnings("unused")
private float mLastMotionY; public ScrollLayout(Context context) {
super(context);
mScroller = new Scroller(context);
mCurScreen = mDefaultScreen;
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
} public ScrollLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
mCurScreen = mDefaultScreen;
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
} public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScroller = new Scroller(context);
mCurScreen = mDefaultScreen;
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int childLeft = 0;
final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) {
final View childView = getChildAt(i);
if (childView.getVisibility() != View.GONE) {
final int childWidth = childView.getMeasuredWidth();
childView.layout(childLeft, 0, childLeft + childWidth,
childView.getMeasuredHeight());
childLeft += childWidth;
}
}
}
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int width = MeasureSpec.getSize(widthMeasureSpec);
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException(
"ScrollLayout only canmCurScreen run at EXACTLY mode!");
} final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException(
"ScrollLayout only can run at EXACTLY mode!");
} final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
// 初始化视图的位置
scrollTo(mCurScreen * width, 0);
} /**
* 根据滑动的距离判断移动到第几个视图
*/
public void snapToDestination(int velocity) {
final int screenWidth = getWidth();
final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;
snapToScreen(destScreen, velocity);
} /**
* 滚动到制定的视图
*
* @param whichScreen 视图下标
*/
public void snapToScreen(int whichScreen, int velocity) {
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
if (getScrollX() != (whichScreen * getWidth())) { final int delta = whichScreen * getWidth() - getScrollX(); // 计算duration
int width = getWidth();
int halfWidth = width / 2;
float distanceRatio = Math.min(1f, 1.0f * Math.abs(delta) / width);
float distance = halfWidth + halfWidth * distanceInfluenceForSnapDuration(distanceRatio);
int duration = 4 * Math.round(1000 * Math.abs(distance / Math.abs(velocity)));
duration = Math.min(duration, MAX_SETTLE_DURATION);
// 开始滚动
mScroller.startScroll(getScrollX(), 0, delta, 0, duration);
mCurScreen = whichScreen;
invalidate();
}
} public void setToScreen(int whichScreen) {
whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
mCurScreen = whichScreen;
scrollTo(whichScreen * getWidth(), 0);
} public int getCurScreen() {
return mCurScreen;
} @Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
} @Override
public boolean onTouchEvent(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event); final int action = event.getAction();
final float x = event.getX(); switch (action) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mLastMotionX = x;
break; case MotionEvent.ACTION_MOVE:
int deltaX = (int) (mLastMotionX - x);
mLastMotionX = x; scrollBy(deltaX, 0);
break; case MotionEvent.ACTION_UP:
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000);
int velocityX = (int) velocityTracker.getXVelocity(); if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {
// 向左移动
snapToScreen(mCurScreen - 1, velocityX);
} else if (velocityX < -SNAP_VELOCITY
&& mCurScreen < getChildCount() - 1) {
// 向右移动
snapToScreen(mCurScreen + 1, velocityX);
} else {
snapToDestination(velocityX);
}
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
mTouchState = TOUCH_STATE_REST;
break;
case MotionEvent.ACTION_CANCEL:
mTouchState = TOUCH_STATE_REST;
break;
} return true;
} float distanceInfluenceForSnapDuration(float f) {
f -= 0.5f; // center the values about 0.
f *= 0.3f * Math.PI / 2.0f;
return (float) Math.sin(f);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE)
&& (mTouchState != TOUCH_STATE_REST)) {
return true;
} final float x = ev.getX();
final float y = ev.getY(); switch (action) {
case MotionEvent.ACTION_MOVE:
final int xDiff = (int) Math.abs(mLastMotionX - x);
if (xDiff > mTouchSlop) {
mTouchState = TOUCH_STATE_SCROLLING;
}
break; case MotionEvent.ACTION_DOWN:
mLastMotionX = x;
mLastMotionY = y;
mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
: TOUCH_STATE_SCROLLING;
break; case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mTouchState = TOUCH_STATE_REST;
break;
} return mTouchState != TOUCH_STATE_REST;
} }

【转载/修改】ScrollLayout代码修正,追加模仿viewpager滚动速度的更多相关文章

  1. 数据库分库分表(sharding)系列(五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案

    作为一种数据存储层面上的水平伸缩解决方案,数据库Sharding技术由来已久,很多海量数据系统在其发展演进的历程中都曾经历过分库分表的Sharding改造阶段.简单地说,Sharding就是将原来单一 ...

  2. HOOK大法实现不修改程序代码给程序添加功能

    [文章标题]: HOOK大法实现不修改程序代码给程序添加功能[文章作者]: 0x18c0[软件名称]: Scylla[使用工具]: OD.Stub_PE.ResHacker[版权声明]: 本文原创于0 ...

  3. DB 分库分表(5):一种支持自由规划无须数据迁移和修改路由代码的 Sharding 扩容方案

    作为一种数据存储层面上的水平伸缩解决方案,数据库Sharding技术由来已久,很多海量数据系统在其发展演进的历程中都曾经历过分库分表的Sharding改造阶段.简单地说,Sharding就是将原来单一 ...

  4. 用ildasm/ilasm修改IL代码

    原文地址:http://www.cnblogs.com/dudu/archive/2011/05/17/ildasm_ilasm_il.html 在开发中遇到这样一个场景,需要修改一个dll文件(.N ...

  5. 如何用chrome修改js代码,跳过网站等待时间

    用chrome修改js代码 By Z.H. Fu 切问录 [maplewizard.github.io](http://maplewizard.github.io ) 网页中大部分的限制都是由js编写 ...

  6. 翻译文章“AST 模块:用 Python 修改 Python 代码”---!!注意ironpathyon未实现此功能

    https://github.com/upsuper/blog/commit/0214fdd084c4adf2de2ed9912d644fb59ce13a1c +Title: [翻译] AST 模块: ...

  7. 【Eclipse】修改java代码不强制重启

    找到tomcat的server.xml文件,修改以下代码,重新发布重启.然后修改java代码就可以不用重启了. 将reloadable=“true”改成reloadable="false&q ...

  8. 本地修改js代码并时时生效的解决办法

    js作为客户端语言(当然它也可以作服务端语言),非常强悍,一般情况下,我们都是在开发阶段不停的改,然后上线之后就作为稳定运行的代码. 然而有时候可能因为js写得有问题,导致上线后,某些功能无法使用,这 ...

  9. git push完代码 想撤回 并保留之前修改的代码 / 修改完代码 发现分支不对 想切换分支 /恢复已修改的文件

    git reset --soft xxxx // xxxx是版本号 回退 git stash //保留当前分支修改的代码 git checkout xxx //切换到xxx分支 git stash l ...

随机推荐

  1. 挣值管理(EVT)

    如果你对项目管理.系统架构有兴趣,请加微信订阅号"softjg",加入这个PM.架构师的大家庭 第二个大计算,根据PV.EV.AC计算出CV.SV.SPI.CPI.ETC.EAC. ...

  2. $(function(){})与 (function(){})() (function($){})() 的区别

    1. $(function(){ }) 或 jQuery(function(){ }) 此函数也可以写成 jQuery(function(){ }), 用于存放操作DOM对象的代码,执行其中代码时DO ...

  3. 洛谷P1457 城堡 The Castle

    P1457 城堡 The Castle 137通过 279提交 题目提供者该用户不存在 标签USACO 难度提高+/省选- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 我们憨厚的USACO ...

  4. JS与JQ倒计时的写法

    页面需要制作一个倒计时的功能:然后度娘了一遍,找到两种写法,原生JS与JQ 的,经过测试原生JS在IE可能会有不刷新的现象所以结合了一个大神的JQ写法修改好了一个. 原生JS写法: HTML: < ...

  5. C# 反射操作方法

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.R ...

  6. hbase基本结构

    HBASE  基本结构一.overview1. hbase <=> NOSQL     不错,hbase 就是某种类型的nosql 数据库,唯一的区别就是他支持海量的数据.    hbas ...

  7. A planning attack on a commuter train carriage in Taipei

    Last night an explosion on a commuter train carriage in Taipei Songshan railway station wounded at l ...

  8. java 字节流和字符流的区别

    转载自:http://blog.csdn.net/cynhafa/article/details/6882061 java 字节流和字符流的区别 字节流与和字符流的使用非常相似,两者除了操作代码上的不 ...

  9. puppet实现主从部署各种软件实战参考模型

    puppet实现主从部署各种软件实战参考模型   实验要求:     1.我将准备三个节点 node2 , node3 , node4 2.我们想让节点node3部署ntp,nginx ;节点node ...

  10. IOS 支付功能的实现

    支付宝是第三方支付平台,简单来说就是协调客户,商户,银行三者关系的方便平台 使用支付宝进行一个完整的支付功能,大致有以下步骤: a 与支付宝进行签约,获得商户ID(partner)和账号ID(sell ...