Android实现滑动的七种方式
来源:互联网 发布:快网域名 编辑:程序博客网 时间:2024/06/06 03:51
1. layout方法
根据用户手指滑动的位置(ACTION_MOVE),记录每次小段的偏移量(offset),通过layout不停对view进行重新布局,完成view的移动效果。
a). 使用视图坐标系:getX(),getY()
@Override public boolean onTouchEvent(MotionEvent event) { // 这里需要转换为int值,保证layout方法参数 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY); break; } // 返回false不能达到滑动的目标 return true; }}
由于每次layout后,触摸点相对于父控件的位置不变,因此滑动期间不需要更新mLastX和mLastY的值。
b). 使用Android坐标系:getRawX(),getRawY()
@Override public boolean onTouchEvent(MotionEvent event) { // 这里需要转换为int值,保证layout方法参数 int x = (int) event.getRawX(); int y = (int) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY); // 需要更新mLastX与mLastY的值 mLastX = x; mLastY = y; break; } // 返回false不能达到滑动的目标 return true; }
需要注意的是,每次move更新界面后都要更新上一次的坐标值,否则下一次布局时会加上控件到屏幕边缘的距离。
2. offsetLeftAndRight()、offsetTopAndBottom()方法:和第一种方法没啥区别
@Override public boolean onTouchEvent(MotionEvent event) { // 这里需要转换为int值,保证layout方法参数 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; offsetLeftAndRight(offsetX); offsetTopAndBottom(offsetY); break; } // 返回false不能达到滑动的目标 return true; }
3. layoutParams: 利用设置边距完成view的移动
@Override public boolean onTouchEvent(MotionEvent event) { // 这里需要转换为int值,保证layout方法参数 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams(); layoutParams.leftMargin = getLeft() + offsetX; layoutParams.topMargin = getTop() + offsetY; setLayoutParams(layoutParams); break; } // 返回false不能达到滑动的目标 return true; }
注意:使用ViewGroup必须保证该控件有一个父布局,否则不能使用
4. scrollBy、scrollTo:瞬间移动
@Override public boolean onTouchEvent(MotionEvent event) { // 这里需要转换为int值,保证layout方法参数 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; // scrollBy和scrollTo的移动方向为屏幕移动方向,与控件移动方向相反 // scrollBy移动的是content,不是view ((View) getParent()).scrollBy(-offsetX, -offsetY); break; } // 返回false不能达到滑动的目标 return true; }
注意:scroll方法移动的不是控件本身,而是其内容。举例来说,View为ViewGroup时,移动的是其全部子控件;View为TextView时,移动的是其文字内容。
5. Scroller:实现平滑移动,在移动模块的同时增加松手后回弹至初始位置的功能。
public class Rect extends View { private int mLastX; private int mLastY; private Scroller mScroller; public Rect(Context context, AttributeSet attrs) { super(context, attrs); mScroller = new Scroller(context); } @Override public void computeScroll() { super.computeScroll(); // 如果Scroller还在计算中,则另其移动 if (mScroller.computeScrollOffset()) { ((View)getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } } @Override public boolean onTouchEvent(MotionEvent event) { // 这里需要转换为int值,保证layout方法参数 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; // scrollBy和scrollTo的移动方向为屏幕移动方向,与控件移动方向相反 // scrollBy移动的是content,不是view ((View) getParent()).scrollBy(-offsetX, -offsetY); break; case MotionEvent.ACTION_UP: View viewGroup = (View) getParent(); // 这里的起始坐标为content的起始坐标,而不是view的起始坐标 mScroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY()); invalidate(); } // 返回false不能达到滑动的目标 return true; }}步骤分为:初始化Scroller对象——复写computeScroll函数——调用Scroller对象的startScroll函数开启滑动过程
6. 属性动画
后期待添加
7. ViewDragHelper
xml文件:
<?xml version="1.0" encoding="utf-8"?><com.example.tianshuhe.learningcomponent.DragFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.tianshuhe.learningcomponent.MainActivity"> <View android:id="@+id/menu_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"/> <View android:id="@+id/main_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_red_light"/></com.example.tianshuhe.learningcomponent.DragFrameLayout>
自定义的DragFrameLayout文件:
package com.example.tianshuhe.learningcomponent;import android.content.Context;import android.support.v4.view.ViewCompat;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.FrameLayout;/** * Created by tianshuhe on 17/8/22. */public class DragFrameLayout extends FrameLayout { private ViewDragHelper mViewDragHelper; private ViewDragHelper.Callback mCallback; private View mMainView, mMenuView; public DragFrameLayout (Context context, AttributeSet attrs) { super(context, attrs); initView(); } private void initView() { mCallback = new ViewDragHelper.Callback() { @Override // 只拦截主界面的滑动事件 public boolean tryCaptureView(View child, int pointerId) { return mMainView == child; } // 设置水平滑动事件 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return left; } @Override public int clampViewPositionVertical(View child, int top, int dy) { return 0; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); // 根据滑动的大小,设置是否显示全部的菜单 // 这种实现方式实际上是一开始menu被main阻挡,后期main被拿开 if (mMainView.getLeft() < 500) { mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0); ViewCompat.postInvalidateOnAnimation(DragFrameLayout.this); } else { mViewDragHelper.smoothSlideViewTo(mMainView, 300, 0); ViewCompat.postInvalidateOnAnimation(DragFrameLayout.this); } } }; mViewDragHelper = ViewDragHelper.create(this, mCallback); } // 拦截点击事件 @Override public boolean onTouchEvent(MotionEvent event) { mViewDragHelper.processTouchEvent(event); return true; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // 这里一开始main和menu使用自定义的滑动view,则返回true,否则不能实现效果 return mViewDragHelper.shouldInterceptTouchEvent(ev); } @Override public void computeScroll() { if (mViewDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } @Override protected void onFinishInflate() { super.onFinishInflate(); mMainView = findViewById(R.id.main_view); mMenuView = findViewById(R.id.menu_view); }}
一个奇怪的现象:onInterceptTouchEvent中,如果本身的控件带有滑动效果,这种方式返回后并不会对其事件进行拦截,这种情况待后续分析。
阅读全文
0 0
- Android实现滑动的七种方式
- Android实现滑动的七种方法
- Android实现滑动的七种方法
- Android 实现滑动的七种方法
- View滑动效果的七种实现方式
- 实现View滑动的七种方式记录
- Android实现滑动的几种方式
- Android滑动实现的六种方式
- Android Scroll分析--实现滑动的七种方法
- 实现滑动的七种方法(Android群英传)
- Android实现滑动的七种方法实践
- Android之实现滑动的七种方法总结
- Android之实现滑动的七种方法总结
- Android中实现滑动的七种方法
- Android 实现 View 滑动的七种方法
- 滑动效果的七种方式
- 实现滑动的七种方法
- 实现View滑动的七种方法
- arcgis api for javascript 4.4 开发环境搭建
- ifconfig出现command not found解决办法
- shiro.xml配置
- 【深入PHP 面向对象】读书笔记(四)
- 练习 2017-08-22 通过控制台,获取类名,字段名称,字段类型,根据一个模板文件,自动创建这个类文件,并且为字段提供setter和getter方法
- Android实现滑动的七种方式
- 【Linux】readv与writev
- 十一 iOS 图片截取
- 滑动窗口
- hdu6152暴力暴力!!!
- 语音信号的采样和量化
- redmine操作教程
- linux 安装 mysql
- 使用PageHelper实现分页