ViewDragHelper简介
2016-07-03 13:42
381 查看
1,概述
简单地来说,ViewDragHelper是一个实现滑动布局的辅助类。比如Google在support库中提供的DrawerLayout布局,就是用ViewDragHelper来实现的。虽然现在有现成的滑动布局可以供我们使用,但是只有掌握ViewDragHelper的用法,我们才能够更加灵活地自定义我们需要的控件。
通常,ViewDragHelper用在一个自定义的ViewGroup中。在自定义控件的过程中,除了实现callback的一些方法外,也要重写该ViewGroup的一些方法。
2,ViewGroup需要重写的方法
加载布局@Override protected void onFinishInflate() { super.onFinishInflate(); mMenuView=getChildAt(0); mMainView=getChildAt(1); }
在本实例中,有两个子布局。一个是菜单布局,一个是主布局。
2.获取布局控件的大小
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth=mMenuView.getMeasuredWidth(); }
在该方法中,可以获得一些控件的大小。该方法不一定需要重写。如果需要获得控件大小的话,该方法需要重写,否则不需要重写。在本例中是不需要获取某个控件的大小,这里只是举例说明该方法的用法。
3.事件拦截
/** * 将事件传递给ViewDragHelper。 * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDragHelper.shouldInterceptTouchEvent(ev); } /** * 返回true表示:事件不再继续向下传递,到本ViewGroup为止。 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { mViewDragHelper.processTouchEvent(event); return true; }
这两个方法必须要重写。
4.滑动时视图的绘制方法
/** * *Scroller的核心方法,系统在绘制View的时候会在draw()方法中调用该方法。 *如果在继续滚动,mViewDragHelper.continueSettling(true)返回值为true,视图进行更新。*/ @Override public void computeScroll() { if(mViewDragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } }
3,ViewDragHelper.Callback常用方法介绍
@Override public boolean tryCaptureView(View child, int pointerId) { return mMainView==child; }
该方法表示什么时候开始检测事件,返回true表示开始检测滑动事件。更直观的理解就是,返回哪个View,哪个View就可以滑动。在本例中,只需要主布局mMainView可以滑动。
@Override public int clampViewPositionHorizontal(View child, int left, int dx) { /** * dx描述的是速度 */ Log.i("liang","left is"+left); Log.i("liang","dx is"+dx); if(left<0){ left=0;//使其不能向左滑动 } return left; } @Override public int clampViewPositionVertical(View child, int top, int dy) { return 0; }
这是两个实现滑动的具体方法。如果是水平滑动,则需要重写第一个方法。如果是垂直滑动,则需要重写第二个方法。
这两个方法返回0表示不能滑动。left和top这两个参数分别表示在水平方向和垂直方向上滑动的距离(严格的来说是x和y方向上的坐标)。
在本例中,我们是水平滑动的,因此需要重写clampViewPositionHorizontal(View child, int left, int dx)方法。而clampViewPositionVertical(View child, int top, int dy)我们返回0或者不去重写。
在第一个方法中,如果我们只返回left,那么主布局便可以左右滑动,这样显然不是我们需要的,一般情况下侧滑只需要右滑动即可。left<0表示向左滑动,因此一旦检测出用户有向右滑动的手势,那么我们就直接返回0,不去响应滑动事件。
@Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if(mMainView.getLeft()<300){ mViewDragHelper.smoothSlideViewTo(mMainView,0,0); ViewCompat.postInvalidateOnAnimation(DragViewGroup.this); }else{ mViewDragHelper.smoothSlideViewTo(mMainView, 500, 0); ViewCompat.postInvalidateOnAnimation(DragViewGroup.this); } }
该方法实现手指离开屏幕后实现的操作。
滑动后,如果主布局距离左侧少于300个像素,则通过mViewDragHelper.smoothSlideViewTo(mMainView,0,0)使主布局停留在起始的位置。即左上角的坐标仍为(0,0)。
如果距离左侧的像素大于300,则使主布局左上角停留在坐标为(500,0)的位置上。即主布局距离左侧有500个像素,这样,菜单布局就显示出来了。
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this)是用来刷新视图的。每次主布局的坐标改变后,该方法通知UI线程刷新画面。
除了这几个方法之外,onViewCaptured(),onViewDragStateChanged(),onViewPositionChanged()等方法。有兴趣的读者可以自行查看其用法。
4,源码
自定义的ViewCroup:DragViewGrouppublic class DragViewGroup extends FrameLayout {
private ViewDragHelper mViewDragHelper;
private View mMenuView,mMainView;
private int mWidth;
private Context context;
public DragViewGroup(Context context) {
super(context);
this.context=context;
initView();
}
public DragViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
initView();
}
public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context=context;
initView();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMenuView=getChildAt(0);
mMainView=getChildAt(1);
}
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth=mMenuView.getMeasuredWidth(); }
/**
* 将事件传递给ViewDragHelper。
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
/**
* 返回true表示:事件不再继续向下传递,到本ViewGroup为止。
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
private void initView(){
mViewDragHelper=ViewDragHelper.create(this,callback);
}
private ViewDragHelper.Callback callback=new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return mMainView==child;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
/**
* dx描述的是速度
*/
Log.i("liang","left is"+left);
Log.i("liang","dx is"+dx);
if(left<0){
left=0;//使其不能向左滑动
}
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); if(mMainView.getLeft()<300){ mViewDragHelper.smoothSlideViewTo(mMainView,0,0); ViewCompat.postInvalidateOnAnimation(DragViewGroup.this); }else{ mViewDragHelper.smoothSlideViewTo(mMainView, 500, 0); ViewCompat.postInvalidateOnAnimation(DragViewGroup.this); } }
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
}
};
/**
*
*Scroller的核心方法,系统在绘制View的时候会在draw()方法中调用该方法。
*如果在继续滚动,mViewDragHelper.continueSettling(true)返回值为true,视图进行更新。*/
@Override
public void computeScroll() {
if(mViewDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
2.布局文件:activity_main
包含两个子布局,menuLayout和mainLayout
<widget.DragViewGroup xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <RelativeLayout android:id="@+id/mennuLyout" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="vertical" > <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/rl1" > <ImageView android:id="@+id/id_img1" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:src="@mipmap/img_1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_toRightOf="@id/id_img1" android:text="第一个Item" android:textColor="@android:color/black" android:textSize="20sp" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/id_img2" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:src="@mipmap/img_2" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_toRightOf="@id/id_img2" android:text="第二个Item" android:textColor="@android:color/black" android:textSize="20sp" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/id_img3" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:src="@mipmap/img_3" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_toRightOf="@id/id_img3" android:text="第三个Item" android:textColor="@android:color/black" android:textSize="20sp" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/id_img4" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:src="@mipmap/img_4" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_toRightOf="@id/id_img4" android:text="第四个Item" android:textColor="@android:color/black" android:textSize="20sp" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/id_img5" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:src="@mipmap/img_5" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_toRightOf="@id/id_img5" android:text="第五个Item" android:textColor="@android:color/black" android:textSize="20sp" /> </RelativeLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/id_img6" android:layout_width="50dp" android:layout_height="50dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:src="@mipmap/img_1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="20dp" android:layout_toRightOf="@id/id_img6" android:text="第一个Item" android:textColor="@android:color/black" android:textSize="20sp" /> </RelativeLayout> </LinearLayout> </RelativeLayout> <RelativeLayout android:id="@+id/mainLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/zhangdi" /> </RelativeLayout> </widget.DragViewGroup>
3.效果图
滑动之前的效果。主界面仅仅是一张图片
滑动后,菜单布局显示出来了
相关文章推荐
- Android布局的小窍门?
- Web布局连载——两栏固定布局(五)
- 谷歌正式开始补偿Nexus 6P重启门和电池门用户:最高赔400美元
- 每日安全资讯:谷歌发现 G Suite 漏洞,部分密码明文存储长达十四年
- 每日安全资讯:命案侦破过程揭示 Google 能够跟踪全世界的手机
- flex 控件的重要属性
- 学习Winform文本类控件(Label、Button、TextBox)
- 谷歌、雅虎支持中文域名搜索 有助提升搜索引擎优化
- Delphi控件ListView的属性及使用方法详解
- 样式表CSS布局经验
- 在winform下实现左右布局多窗口界面的方法之续篇
- web下载的ActiveX控件自动更新
- WinForm实现按名称递归查找控件的方法
- css网页布局中注意的几个问题小结
- DL.DT.DD实现左右的布局简单例子第1/2页
- 使用CSS框架布局的缺点和优点小结
- div+CSS网页布局的意义与副作用原因小结第1/2页
- C#中父窗口和子窗口之间控件互操作实例
- 在winform下实现左右布局多窗口界面的方法
- C#编写ActiveX网页截图控件