您的位置:首页 > 其它

安卓开发之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_content

import 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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ViewDrag helper