Scroller的用法,VelocityTracker用法,以及滑动冲突的处理
2016-12-14 21:36
435 查看
参考:http://blog.csdn.net/yanghuinipurean/article/details/50419455
/** * 仿微信刷新 * @author Nipuream */ public class WXLayout extends LinearLayout{ private static final String TAG = "WXLayout"; private int mTouchSlop; private boolean mIsBeingDragged = false; private float mLastMotionY; private float mInitialMotionY; private float resistance = 0.6f; private Scroller mScroller; private ListView mListView; private boolean isMove = false; private int duration = 300; private ScrollRershListener l; private boolean isRersh = false; public WXLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(context); } private void init(final Context context){ ViewConfiguration config = ViewConfiguration.get(context); mTouchSlop = config.getScaledTouchSlop(); DecelerateInterpolator interpolator = new DecelerateInterpolator(); mScroller = new Scroller(context,interpolator); post(new Runnable() { @Override public void run() { // ?主线程的最后才获取mListView? mListView = (ListView) WXLayout.this.getChildAt(0); } }); } //处理滑动冲突 public boolean onInterceptTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub final int action = ev.getAction(); //手势抬起和取消,不阻碍事件传递 if(action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP){ mIsBeingDragged = false; return false; } //如果mIsBeingDragged为true表示正在拖动,那么除了down事件都不发送给子元素 //down事件应该要发给子元素,因为down触发时,不能判定之后父元素是否会滑动,从而拦截子元素的事件 if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) { return true; } switch(action){ case MotionEvent.ACTION_DOWN:{ //记录按下的位置,down事件一定会走到此处 mLastMotionY = mInitialMotionY = ev.getY(); mIsBeingDragged = false; break; } case MotionEvent.ACTION_MOVE:{ final float y = ev.getY(), x = ev.getX(); final float diff, absDiff; diff = y - mLastMotionY; absDiff = Math.abs(diff); if(absDiff > mTouchSlop){ //如果滑动的距离足够大 if(diff > 1){ //并且是手指向下滑动 //并且ListView的第一个元素已经可以被看到了 if(mListView.getFirstVisiblePosition()==0){ View view = mListView.getChildAt(0); Rect rect = new Rect (); view.getLocalVisibleRect(rect); //并且第一个元素已经滑到listView的顶部了 if(rect.top == 0){ //那么事件将由listView的父元素接管,来模拟微信的效果, //mInitialMotionY应该在此处赋值,当作滑动的起始点 mLastMotionY = y; mIsBeingDragged = true; } } } } break; } } return mIsBeingDragged; } @Override public boolean 4000 onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub //如果碰触到控件的边缘,就不接受这一系列的action了 if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) { return false; } //如果Scroller正在滑动,就不接受这次事件了 if(isMove){ return false; } switch(event.getAction()){ case MotionEvent.ACTION_DOWN:{ //因为此Layout元素不会拦截down事件,所以按理说执行不到此处? mLastMotionY = mInitialMotionY = event.getY(); return true; } case MotionEvent.ACTION_MOVE:{ if (mIsBeingDragged) { if(l!=null && !isRersh){ l.startRersh(); isRersh = true; } mLastMotionY = event.getY(); float moveY = mLastMotionY - mInitialMotionY; //计算layout的滑动距离 if(l != null){ l.Rersh(moveY); } if(moveY > 0){ //设置layout的下拉位置 int value = (int) Math.abs(moveY); scrollTo(0, - (int)(value*resistance)); } return true; } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP:{ //将layout用动画mScroller.startScroll来复原 if(mIsBeingDragged){ mIsBeingDragged = false; startMoveAnim(getScrollY(), Math.abs(getScrollY()), duration); if(l!= null && isRersh && (event.getY() - mInitialMotionY) > 0){ l.endRersh(event.getY() - mInitialMotionY); isRersh = false; } return true; } break; } } return super.onTouchEvent(event); } public void startMoveAnim(int startY, int dy, int duration) { isMove = true; mScroller.startScroll(0, startY, 0, dy, duration); invalidate();//通知UI线程的更新 } @Override public void computeScroll() { //判断是否还在滚动,还在滚动为true if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //更新界面 postInvalidate(); isMove = true; } else { isMove = false; } super.computeScroll(); } public interface ScrollRershListener{ void Rersh(float value); void startRersh(); void endRersh(float value); } public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } public void setOnScrollRershListener(ScrollRershListener l){ this.l = l; } }
/** * 仿QQ侧滑删除 * @author Nipuream * */ public class SlideListView extends ListView implements OnTouchListener,OnClickListener{ private static final String TAG = "SlideListView"; private Context mContext; private Scroller mScroller; /** * 初始值 */ private float initalXvalue,mLastXvalue; private float initalYvalue,mLastYvalue; /** * 确认滑动的最小速度 */ private int MIN_VELOCITY = 800; /** * 速度跟踪器 */ private VelocityTracker velocityTracker; /** * 正在被拖动的view */ private View dragView; /** * 正在被拖动的position */ private int touchPos; /** * 默认的最小滑动距离 */ private int mTouchSlop; /** * 滑动时间 */ private int DURATION_TIME = 300; /** * 出现删除按钮的Item */ private View tempView ; /** * 出现删除按钮的position */ private int tempPos ; /** * 删除按钮 */ private Button deleteBtn; /** * 移除接口 */ private RemoveItemListener l; /** * 是否可以滑动 */ private boolean isSlide = false; public SlideListView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(context); } private void init(Context context){ mContext = context; AccelerateInterpolator interpolator = new AccelerateInterpolator(); mScroller = new Scroller(context,interpolator); velocityTracker = VelocityTracker.obtain(); ViewConfiguration config = ViewConfiguration.get(context); mTouchSlop = config.getScaledTouchSlop(); setOnTouchListener(this); } /** * 捕捉用户到底拖动了哪个view * 拦截事件 */ //此方法一定会被调用,所以在此方法内纪录触摸到的Item public boolean dispatchTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub final int action = ev.getAction(); if (action == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { return false; } if(action == MotionEvent.ACTION_DOWN){ mLastXvalue = initalXvalue = ev.getX(); mLastYvalue = initalYvalue = ev.getY(); //正在滑动时,事件继续分发 if(!mScroller.isFinished()){ return super.dispatchTouchEvent(ev); } //通过点击位置,查出所点击的Item的索引 touchPos = pointToPosition((int)mLastXvalue, (int)mLastYvalue); if(touchPos == AdapterView.INVALID_POSITION){ return super.dispatchTouchEvent(ev); } GetTracker(ev); //取得当前触摸的Item dragView = getChildAt(touchPos - getFirstVisiblePosition()); isSlide = false; }else if(action == MotionEvent.ACTION_MOVE){ mLastXvalue = ev.getX(); mLastYvalue = ev.getY(); if(velocityTracker == null){ GetTracker(ev); } velocityTracker.computeCurrentVelocity(1000); //当横向滑动速度足够大,或者横向滑动距离足够大时,标记Item为可以滑动 if(Math.abs(velocityTracker.getXVelocity()) > MIN_VELOCITY ||Math.abs(mLastXvalue - initalXvalue)> mTouchSlop && Math.abs(mLastYvalue - initalYvalue) < mTouchSlop){ isSlide = true; } }else if(action == MotionEvent.ACTION_UP){ CloseTracker(); } return super.dispatchTouchEvent(ev); } /** * 消费事件 */ @Override public boolean onTouchEvent(MotionEvent ev) { if(isSlide){ switch(ev.getAction()){ case MotionEvent.ACTION_MOVE: { mLastXvalue = ev.getX(); final float moveX = mLastXvalue - initalXvalue; //横向滑动大于特定值时,dragView跟随手指的位置向左移动 if(Math.abs(moveX) > dip2px(mContext, 20)) { if(moveX < 0 && Math.abs(moveX)<dip2px(mContext, 100)) { if(dragView != null){ dragView.scrollTo(Math.abs((int)moveX), 0); } return true; } } } break; case MotionEvent.ACTION_UP: { mLastXvalue = ev.getX(); float scrollDistance = mLastXvalue - initalXvalue; //手指抬起时,滑到最左或者划回原位 if(scrollDistance < 0){ if(Math.abs(scrollDistance) < dip2px(mContext, 50)){ //滑动回去 if(dragView != null){ mScroller.startScroll(dragView.getScrollX(), 0, -dragView.getScrollX(), 0, DURATION_TIME); invalidate(); } }else if(Math.abs(scrollDistance) > dip2px(mContext, 50) ){ //滑动到底 if(dragView != null){ mScroller.startScroll(dragView.getScrollX(), 0, (dip2px(mContext, 100) - Math.abs(dragView.getScrollX())), 0,DURATION_TIME); invalidate(); tempView = dragView; tempPos = touchPos; setListener(); } } } } break; } } return super.onTouchEvent(ev); } private void GetTracker(MotionEvent ev){ if(velocityTracker == null){ velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(ev); } private void CloseTracker() { if(velocityTracker != null){ velocityTracker.recycle(); velocityTracker.clear(); velocityTracker = null; } } private void setListener(){ deleteBtn = (Button) tempView.findViewById(R.id.delete); deleteBtn.setOnClickListener(this); } @Override public void computeScroll() { // TODO Auto-generated method stub if(mScroller.computeScrollOffset()){ dragView.scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } super.computeScroll(); } public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } @Override //返回true将使onTouchEvent无法触发,当某个Item左滑后显示出delete按钮, //则点击整个layout时,Item复位,且onTouchEvent不能被触发 public boolean onTouch(View v, MotionEvent event) { if(tempView != null){ dragView = tempView ; mScroller.startScroll(dragView.getScrollX(), 0, - dragView.getScrollX(), 0,DURATION_TIME); invalidate(); deleteBtn.setOnClickListener(null); deleteBtn = null; tempView = null; return true; } return false; } @Override //点击delete按钮的回调 public void onClick(View v) { // TODO Auto-generated method stub if(l != null){ l.remove(tempPos); dragView = tempView; dragView.scrollTo(0, 0); tempView = null; invalidate(); } } public interface RemoveItemListener{ void remove(int pos); } public void setOnRemoveItemListener(RemoveItemListener l){ this.l = l; } }
相关文章推荐
- 网络流ISAP模板
- 样式和主题
- [POLITICS] S Korea lawmakers vote to impeach leader
- Nodejs源码解析之module
- laravel5.2总结--集合
- 音频噪声抑制(5):含辅助观测数据的LMS噪声抑制
- 机器学习-线性回归python简单实现
- Linux文件权限学习笔记
- Codeforces Round #383 (Div. 2) D 分组背包
- gabor变换人脸识别的python实现,att_faces数据集平均识别率99%
- web中常见的bug调试总结
- 172.16.82.0/25的含义,IP段,掩码
- Android下的帧动画
- 三种设置session的失效时间
- poj_1200_Crazy Search_hash
- kettle定时任务_第三方合作方有订单自动发送邮件通知_20161214
- 3 HTML&JS等前端知识系列之javascript的基础
- 线性模型
- MySQL(五) MySQL中的索引详讲
- 阿里云服务器被黑