安卓开发之ViewDragHelper的使用及自定义可下拉展示内容的ViewGroup
2016-08-22 20:29
507 查看
一、ViewDragHelper
一个自定义ViewGroup的工具类,它提供了许多有用的方法和状态允许用户去拖拽和绘制子View在自定义ViewGroup中的轨迹和位置。ViewDragHelper可以使用静态方法创建一个实例:
ViewDragHelper.create(ViewGroup forParent,int sensitiveity,ViewDragHelper.Callback cb)
在自定义ViewGroup中,ViewDragHelper可以帮助我们来分析手势和处理拖动:
@Override public boolean onTouchEvent(MotionEvent event) { try { //处理触摸事件 mDragHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } //返回true, return true; }
使用ViewDragHelper来动态移动自定义ViewGroup中的控件:
public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop) // Animate the view child to the given (left, top) position. // 返回true 代表还没有移动到指定的位置,需要刷新界面,继续移动 // 返回false 就停止工作
使用ViewDragHelper滑动边缘监听:
// 监听左边缘滑动 setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
二、 ViewDragHelper.Callback
ViewDragHelper.Callback集成了许多可覆写的方法,所有移动的控制在ViewDragHelper.Callback里面来实现。是否可以捕捉ViewGroup中的子组件:
public boolean tryCaptureView(View child, int pointerId) { //返回true,就代表着可对该子组件处理滑动事件。否则就不会处理。 return true; //只对特定的组件捕捉 return speChild == child; }
// 使用ViewDragHelper的captureChildView捕捉子组件,该方法可以绕过tryCaptureView方法
clampViewPositionHorizontal[Vertical]:
处理子组件在水平或者竖直方向的滑动限制,在这个方法内部做子组件的边界处理,就是确保子组件不会滑过界。
例如在竖直方向进行滑动时,一般先获取控件可滑动到的顶端Y值和底端Y值,再进行一个取值
@Override public int clampViewPositionVertical(View child, int top, int dy) { //手指触摸移动时实时回调, top表示要到的y位置 int topBound = ...; int bottomBound = ...; return Math.min(Math.max(topBound, top), bottomBound); }
onViewPositionChanged
当前拖动的子组件位置变化时调用的方法。一般在该方法里调整其他子组件的位置。
@Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { //changedView为当前位置发生改变的View,left,top分别为该View的left和top坐标 }
onViewReleased
当手指释放的时候会调用的方法。在这个方法里实现松开时的滑动效果。
@Override public void onViewReleased(View releasedChild, float xvel, float yvel) { //released 为释放的View,xvel,yvel分别为该手指离开时滑动和竖直滑动的速度 }
getViewVertical[Horizontal]DragRangeHorizontal
@Override public int getViewVerticalDragRange(View child) { //返回当前捕捉的child子组件的竖直滑动范围 return ...; }
onEdgeDragStarted(int edgeFlags, int pointerId)
// 边缘滑动时回调 @Override public void onEdgeDragStarted(int edgeFlags, int pointerId) { // edgeFlags为边缘滑动的方法标志 }
……
三、ViewDragHelper的使用
自定义可下拉展示内容的的ViewGroup效果图:
一、自定义ViewGroup:DragDownLayout
可支持padding和子组件宽高的wrap_contentimport android.annotation.TargetApi; import android.content.Context; import android.graphics.Rect; import android.os.Build; import android.support.v4.view.MotionEventCompat; import android.support.v4.view.ViewCompat; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; /** * Created by cxm on 2016/8/22. */ public class DragDownLayout extends ViewGroup { private ViewDragHelper dragHelper; private View mDragbar, mContentView; private int dragRange; private OnOpenListener mOnOpenListener; private OnCloseListener mOnCloseListener; private boolean isOpen;//是否打开着 public DragDownLayout(Context context) { super(context); init(); } public DragDownLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public DragDownLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public DragDownLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } private void init() { dragHelper = ViewDragHelper.create(this, mCallback); } @Override protected void onLayout(boolean b, int l, int t, int r, int bo) { mDragbar.layout(getPaddingLeft(), getPaddingTop(), getWidth()-getPaddingRight(), mDragbar.getMeasuredHeight()+getPaddingTop()); mContentView.layout(getPaddingLeft(), getPaddingTop()-mContentView.getMeasuredHeight(), getWidth()-getPaddingRight(), getPaddingTop()); } @Override public boolean onInterceptHoverEvent(MotionEvent event) { final int action = MotionEventCompat.getActionMasked(event); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { dragHelper.cancel(); return false; } return dragHelper.shouldInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { dragHelper.processTouchEvent(event); return true; } private ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return child == mDragbar; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { // top为mDragbar的top值 mContentView.layout(getPaddingLeft(), top-mContentView.getHeight(), getWidth()-getPaddingRight(), top ); } @Override public int clampViewPositionVertical(View child, int top, int dy) { int topBound = getPaddingTop();//顶端边界 int bottomBound = getHeight() - mDragbar.getHeight()-getPaddingBottom();//底端边界 return Math.min(Math.max(topBound, top), bottomBound); } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { // 禁止水平滑动 return getPaddingLeft(); } @Override public int getViewVerticalDragRange(View child) { dragRange = mContentView.getMeasuredHeight(); return dragRange; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { if (mContentView.getBottom() - getPaddingTop() > mContentView.getHeight() / 2) { smoothToBottom(); } else if (mContentView.getBottom() - getPaddingTop() <= mContentView.getHeight() / 2) { smoothToTop(); } invalidate(); } }; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mDragbar = getChildAt(0); mContentView = getChildAt(1); measureChild(mDragbar,widthMeasureSpec,heightMeasureSpec); int dragBarHeight = mDragbar.getMeasuredHeight(); measureChild(mContentView,widthMeasureSpec,heightMeasureSpec); int contentHeight = mContentView.getMeasuredHeight(); setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), dragBarHeight+contentHeight+getPaddingBottom()+getPaddingTop()); } private void smoothToTop() { if (dragHelper.smoothSlideViewTo(mDragbar, getPaddingLeft(), getPaddingTop())) { ViewCompat.postInvalidateOnAnimation(this); isOpen = false; if(mOnCloseListener!=null) mOnCloseListener.close(); } } private void smoothToBottom() { if (dragHelper.smoothSlideViewTo(mDragbar, getPaddingLeft(), getHeight()-getPaddingBottom()-mDragbar.getHeight())) { ViewCompat.postInvalidateOnAnimation(this); isOpen = true; if(mOnOpenListener!=null) mOnOpenListener.open(); } } @Override public void computeScroll() { super.computeScroll(); if (dragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } public boolean isOpen(){ return isOpen; } public void openContent(){ if(!isOpen) smoothToBottom(); } public void closeContent(){ if(isOpen) smoothToTop(); } public interface OnOpenListener{ void open(); } public interface OnCloseListener{ void close(); } public void setOnOpenListener(OnOpenListener mOnOpenListener) { this.mOnOpenListener = mOnOpenListener; } public void setOnCloseListener(OnCloseListener mOnCloseListener) { this.mOnCloseListener = mOnCloseListener; } @Override protected void onFinishInflate() { super.onFinishInflate(); if (getChildCount() != 2) { throw new IllegalStateException("Just contain two Views/ViewGroups "); } } }
二、在xml布局文件中使用DragDownLayout
支持DragDownLayout的padding,没有支持子View的margin。拖拽控件和内容控件的高度可wrap_content / 具体值,宽度需为match_parent。
<com.cxmscb.cxm.dtest.DragDownLayout android:id="@+id/myDragDownLayout" android:background="#e0ffff" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:background="#e000ff" android:layout_width="match_parent" android:layout_height="56dp" android:text="欢迎" android:textColor="#ffffff" android:gravity="center_vertical" android:paddingLeft="15dp" android:textSize="19sp" /> <TextView android:id="@+id/content" android:background="#e000ff" android:layout_width="match_parent" android:layout_height="150dp" android:text="Content" android:gravity="center" android:textSize="20sp"/> </com.cxmscb.cxm.dtest.DragDownLayout>
三、对DragDownLayout设置监听
mDragDownLayout = (DragDownLayout) findViewById(R.id.myDragDownLayout); mDragDownLayout.setOnOpenListener(new DragDownLayout.OnOpenListener() { @Override public void open() { Toast.makeText(MainActivity.this,"open",Toast.LENGTH_SHORT).show(); } });
Github:DragDownLayout
相关文章推荐
- 安卓开发之使用ViewDragHelper简单实现Activity左滑返回
- 【FastDev4Android框架开发】神器ViewDragHelper完全解析,妈妈再也不担心我自定义ViewGroup滑动View操作啦~(三十三)
- Android开发,自定义ViewGroup的神器,ViewDragHelper
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- ViewDragHelper完全解析以及对自定义ViewGroup的作用
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- 安卓开发:弹出自定义对话框自动播放视频(仿视频广告效果,使用mediaplayer和surfaceview做播放器)
- 自定义ViewGroup+ViewDragHelper —— 侧滑菜单
- android ViewDragHelper完全解析 自定义ViewGroup神器
- 【译】使用自定义ViewHelper来简化Asp.net MVC view的开发------part2
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- 【译】使用自定义ViewHelper来简化Asp.net MVC view的开发------part3
- Android开发:使用ViewDragHelper实现抽屉拉伸效果
- 使用Bootstrap 3开发响应式网站实践06,使用ListGroup、Thumbnails展示内容
- 安卓开发——自定义ViewGroup
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- 自定义View(三) switch开关按钮 ViewDragHelper的使用初级
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- 使用ViewDragHelper来现实自定义DrawerLayout