使用ViewDragHelper实现的DragLayout开门效果

来源:互联网 发布:单片机LED接线 编辑:程序博客网 时间:2024/03/29 22:49
先看一下图,有个直观的了解,向下拖动handle就“开门了”:



此DragLayout继承自LinearLayout,这样使得布局变的简单。
我把最顶部的View叫做HeadView,中间的叫“把手”HandleView,底部的叫ContentView,姑且这样叫着。
只有把手可以拖动,下面的ContentView不可以!
只要给DragLayout设置一个background,就会产生一个渐变显示背后布局的效果。
由于DragLayout继承自LinearLayout,所以背后的布局不属于DragLayout的范畴,
DragLayout只有三部分组成(HeadView,HandleView,ContentView)。
这样就造成了背后的布局不能响应手势事件(点击,拖动等),为什么?(该问题已经解决,见帖子最后部分)
因为使用ViewDragHelper需要重写onTouchEvent方法:
@Overridepublic boolean onTouchEvent(MotionEvent ev) {mDragHelper.processTouchEvent(ev);return true;}

此方法必须返回true,消费掉了手势事件,所以背后的View就不会响应事件啦。
有无好办法让背后的View也响应事件???
我初步的构想:把背后的View也纳入到DragLayout布局中去,这样DragLayout就不应该继承LinearLayout,最好继承ViewGroup,这样布局的灵活度更高,当然也更繁碎,需要重写onLayout和onMeasure等方法。但至少可以解决背后View不能响应点击事件的问题!(我想应该是这样)

目前只能将就一下,给个初步的DragLayout实现源码:
import android.content.Context;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.widget.LinearLayout;/** *  * @author pythoner * @since 2015-10-23 * */public class DragLayout extends LinearLayout {private ViewDragHelper mDragHelper;private View headView,handleView,contentView;//三个控件private int headViewHeight,handleViewHeight,contentViewHeight;//三个控件高度private boolean isOpen=false;public DragLayout(Context context) {this(context, null);}public DragLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DragLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);mDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback());setOrientation(LinearLayout.VERTICAL);}@Overrideprotected void onFinishInflate() {super.onFinishInflate();headView = findViewById(R.id.headView);handleView = findViewById(R.id.handleView);contentView = findViewById(R.id.contentView);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);headViewHeight = headView.getMeasuredHeight();handleViewHeight = handleView.getMeasuredHeight();contentViewHeight = contentView.getMeasuredHeight();}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {final int action = MotionEventCompat.getActionMasked(ev);if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {mDragHelper.cancel();return false;}return mDragHelper.shouldInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {mDragHelper.processTouchEvent(ev);return true;}@Overridepublic void computeScroll() {super.computeScroll();if (mDragHelper.continueSettling(true)) {ViewCompat.postInvalidateOnAnimation(this);}}class DragHelperCallback extends ViewDragHelper.Callback {@Overridepublic boolean tryCaptureView(View child, int pointerId) {return child == handleView;//只有把手可以拖拽}@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {// final int topBound = getPaddingTop();//只在Y方向上可以拖动,且拖动范围介于HeadView之下final int topBound = getPaddingTop() + headViewHeight;final int bottomBound = getHeight() - handleViewHeight;final int newTop = Math.min(Math.max(top, topBound), bottomBound);return newTop;}@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {super.onViewReleased(releasedChild, xvel, yvel);//向下快速滑动或者向下滑动超过一半的ContentView时(慢速拖动的情况)if(yvel>0||releasedChild.getY()>headViewHeight+contentViewHeight/2){mDragHelper.settleCapturedViewAt((int) handleView.getX(), getHeight() - handleViewHeight);if(onScrollListener!=null){onScrollListener.onOpen(releasedChild);}isOpen=true;}else{mDragHelper.settleCapturedViewAt((int) handleView.getX(), headViewHeight);if(onScrollListener!=null){onScrollListener.onClose(releasedChild);}isOpen=false;}// 需要invalidate()以及结合computeScroll方法一起invalidate();}@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {super.onViewPositionChanged(changedView, left, top, dx, dy);headView.setY(headView.getY() - dy);// contentView.setY(contentView.getY()+dy);//此处不能使用setY(),否则拖动不上去了,why?所以采用了变通的layout()改变位置contentView.layout(contentView.getLeft(), (int) (contentView.getY() + dy), contentView.getRight(),contentView.getBottom());float fraction=(top-headViewHeight)*1.00f/contentViewHeight;//滑动位移比率getBackground().setAlpha((int)(255*(1-fraction)));//背景根据滑动比率产生渐变效果if(onScrollListener!=null){onScrollListener.onScroll(changedView,fraction);}}}public boolean isOpen(){return isOpen;}private OnScrollListener onScrollListener;public void setOnScrollListener(OnScrollListener onScrollListener) {this.onScrollListener = onScrollListener;}interface OnScrollListener{void onScroll(View view,float fraction);void onOpen(View view);void onClose(View view);}}


测试代码:
import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);DragLayout dragLayout=(DragLayout)findViewById(R.id.dragLayout);dragLayout.setOnScrollListener(new DragLayout.OnScrollListener() {@Overridepublic void onScroll(View view, float fraction) {// TODO Auto-generated method stub}@Overridepublic void onOpen(View view) {// TODO Auto-generated method stubLog.i("tag", "============onOpen============");}@Overridepublic void onClose(View view) {// TODO Auto-generated method stubLog.i("tag", "============onClose============");}});TextView tv_head=(TextView)findViewById(R.id.tv_head);TextView tv_content=(TextView)findViewById(R.id.tv_content);tv_head.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubToast.makeText(MainActivity.this, "tv_head clicked", Toast.LENGTH_SHORT).show();}});tv_content.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// TODO Auto-generated method stubToast.makeText(MainActivity.this, "tv_content clicked", Toast.LENGTH_SHORT).show();}});}}


测试布局:
<FrameLayout 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"     android:background="@android:color/holo_orange_dark"    >    <com.example.viewdraghelper.DragLayout        android:id="@+id/dragLayout"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="@android:color/background_dark" >        <FrameLayout            android:id="@+id/headView"            android:layout_width="match_parent"            android:layout_height="200dp"            android:background="@android:color/holo_blue_bright" >            <TextView                android:id="@+id/tv_head"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:gravity="center"                android:text="head"                android:textSize="48sp" />        </FrameLayout>        <TextView            android:id="@+id/handleView"            android:layout_width="match_parent"            android:layout_height="64dp"            android:background="@android:color/holo_blue_dark"            android:gravity="center"            android:text="handle" />        <FrameLayout            android:id="@+id/contentView"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:background="@android:color/holo_blue_bright"            android:focusable="false"            android:focusableInTouchMode="false" >            <TextView                android:id="@+id/tv_content"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:gravity="center"                android:text="content"                android:textSize="48sp" />        </FrameLayout>    </com.example.viewdraghelper.DragLayout></FrameLayout>


整体的项目代码我不提供,有这三个就够了我想。


突然发现
解决背后的布局不能响应手势事件的问题很容易解决
只需要使用boolean isViewUnder = mDragHelper.isViewUnder(handleView, (int) x, (int) y);
判断一下就可以了
修改onTouchEvent()如下:
@Overridepublic boolean onTouchEvent(MotionEvent ev) {try {mDragHelper.processTouchEvent(ev);} catch (Exception e) {// TODO: handle exception}final float x = ev.getX();      final float y = ev.getY();boolean isViewUnder = mDragHelper.isViewUnder(handleView, (int) x, (int) y); return isViewUnder;}

原来很简单的,之前还不知道此方法。

ViewDragHelper.CallBack中每个方法的用法
http://m.blog.csdn.net/blog/coder_nice/44678153


一个可以下滑显示出一个面板的Toolbar。这个library受Drawerlayout的启发,但有别于Drawerlayout显示左右抽屉,这个library会提供下拉toolbar显示一个面板的功能
http://www.jcodecraeer.com/a/opensource/2015/1204/3750.html
  • 大小: 74.5 KB
  • TestViewDragHelper.rar (3.1 MB)
  • 下载次数: 5
  • 查看图片附件
0 0
原创粉丝点击