public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
final float density = getResources().getDisplayMetrics().density;
mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);
final float minVel = MIN_FLING_VELOCITY * density;
mLeftCallback = new ViewDragCallback(Gravity.LEFT);
mRightCallback = new ViewDragCallback(Gravity.RIGHT);
mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);
mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
mLeftDragger.setMinVelocity(minVel);
mLeftCallback.setDragger(mLeftDragger);
mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback);
mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
mRightDragger.setMinVelocity(minVel);
mRightCallback.setDragger(mRightDragger);
//省略
}
/**
* Factory method to create a new ViewDragHelper.
*
* @param forParent Parent view to monitor
* @param cb Callback to provide information and receive events
* @return a new ViewDragHelper instance
*/
public static ViewDragHelper create(ViewGroup forParent, Callback cb) {
return new ViewDragHelper(forParent.getContext(), forParent, cb);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//由ViewDragHelper类来决定是否要拦截事件
return dragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
//由ViewDragHelper类来决定是否要处理触摸事件,这里可能有异常
dragHelper.processTouchEvent(event);
} catch (Exception e) {
e.printStackTrace();
}
//返回true,可以持续接收到后续事件
return true;
}
/**
* Created by mChenys on 2015/12/16.
*/
public class DragLayout extends FrameLayout {
private String TAG = "DragLayout";
private ViewDragHelper dragHelper;
private LinearLayout mLeftContent; //左侧面板
private LinearLayout mMainContent;//主体面板
public DragLayout(Context context) {
this(context, null);
}
public DragLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
//重写此方法,可以获取该容器下的所有的直接子View
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mLeftContent = (LinearLayout) getChildAt(0);
mMainContent = (LinearLayout) getChildAt(1);
}
private void init() {
//step1 通过ViewDragHelper的单例方法获取ViewDragHelper的实例
dragHelper = ViewDragHelper.create(this, mCallback);
}
//step2 传递触摸事件,需要重写onInterceptTouchEvent和onTouchEvent
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//由ViewDragHelper类来决定是否要拦截事件
return dragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
//由ViewDragHelper类来决定是否要处理触摸事件
dragHelper.processTouchEvent(event);
} catch (Exception e) {
e.printStackTrace();
}
//返回true,可以持续接收到后续事件
return true;
}
//step3 重写ViewDragHelper.Callback()的相关回调方法,处理事件
private ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
/**
* 1.改方法是abstract的方法,必须要实现,其返回结果决定当前child是否可以拖拽
* @param child 当前被拖拽的view
* @param pointerId pointerId 区分多点触摸的id
* @return true表示允许拖拽, false则不允许拖拽 ,默认返回false
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
Log.d(TAG, "tryCaptureView:当前被拖拽的view:" + child);
return false;
}
};
}
<?xml version="1.0" encoding="utf-8"?> <mchenys.net.csdn.blog.mytencentqq.view.DragLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/dragLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <!--左侧--> <LinearLayout android:id="@+id/layout_left" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_red_light" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="左侧" android:textSize="30sp" /> </LinearLayout> <!--主体布局--> <LinearLayout android:id="@+id/layout_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_blue_light" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="主体" android:textSize="30sp" /> </LinearLayout> </mchenys.net.csdn.blog.mytencentqq.view.DragLayout>
D/DragLayout: tryCaptureView:当前被拖拽的view:android.widget.LinearLayout{32f4d44b V.E..... ........ 0,0-720,1134 #7f0c0052 app:id/layout_main}
D/DragLayout: tryCaptureView:当前被拖拽的view:android.widget.LinearLayout{32f4d44b V.E..... ........ 0,0-720,1134 #7f0c0052 app:id/layout_main}
D/DragLayout: tryCaptureView:当前被拖拽的view:android.widget.LinearLayout{32f4d44b V.E..... ........ 0,0-720,1134 #7f0c0052 app:id/layout_main}
D/DragLayout: tryCaptureView:当前被拖拽的view:android.widget.LinearLayout{32f4d44b V.E..... ........ 0,0-720,1134 #7f0c0052 app:id/layout_main}
@Override
public boolean tryCaptureView(View child, int pointerId) {
Log.d(TAG, "tryCaptureView:当前被拖拽的view:" + child);
if (child == mMainContent) {
return true; //只有主题布局可以被拖动
}
return false;
}
/**
* 根据建议值修正将要移动到的横向位置,此时没有发生真正的移动
* @param child 当前被拖拽的View
* @param left 新的建议值
* @param dx 水平位置的变化量
* @return
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
Log.d(TAG, "clampViewPositionHorizontal:" + "旧的left坐标oldLeft:" + child.getLeft()
+ " 水平位置的变化量dx:" + dx + " 新的建议值left:" + left);
return super.clampViewPositionHorizontal(child, left, dx); //父类默认返回0
}
tryCaptureView:当前被拖拽的view:android.widget.LinearLayout{23a3c537 V.E..... ........ 0,0-720,1134 #7f0c0052 app:id/layout_main}
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:1 新的建议值left:1
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:12 新的建议值left:12
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:63 新的建议值left:63
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:53 新的建议值left:53
tryCaptureView:当前被拖拽的view:android.widget.LinearLayout{23a3c537 V.E..... ........ 0,0-720,1134 #7f0c0052 app:id/layout_main}
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:-5 新的建议值left:-5
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:-2 新的建议值left:-2
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:-6 新的建议值left:-6
clampViewPositionHorizontal:旧的left坐标oldLeft:0 水平位置的变化量dx:-11 新的建议值left:-11
/**
* 根据建议值修正将要移动到的纵向位置,此时没有发生真正的移动
* @param child 当前被拖拽的View
* @param top 新的建议值
* @param dy 垂直位置的变化量
* @return
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
Log.d(TAG, "clampViewPositionHorizontal:" + "旧的top坐标oldTop:" + child.getTop()
+ " 垂直位置的变化量dy:" + dy + " 新的建议值top:" + top);
return top;
}
/**
* 当capturedChild被捕获时调用
* @param capturedChild 当前被拖拽的view
* @param activePointerId
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
Log.d(TAG, "onViewCaptured:当前被拖拽的view:" + capturedChild);
super.onViewCaptured(capturedChild, activePointerId);
}
/**
* 返回拖拽的范围,不对拖拽进行真正的限制,仅仅决定了动画执行的速度
* @param child
* @return 返回一个固定值
*/
@Override
public int getViewHorizontalDragRange(View child) {
int range = super.getViewHorizontalDragRange(child);
Log.d(TAG, "被拖拽的范围getViewHorizontalDragRange:" + range);
return range;
}
@Override
public int getViewVerticalDragRange(View child) {
return super.getViewVerticalDragRange(child);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 当尺寸有变化的时候调用
mHeight = getMeasuredHeight();
mWidth = getMeasuredWidth();
// 移动的范围
mRange = (int) (mWidth * 0.6f);
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
Log.d(TAG, "clampViewPositionHorizontal 建议值left:" + left + " mRange:" + mRange);
if (left > mRange) {
left = mRange;
} else if (left < 0) {
left = 0;
}
return left;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
Log.d(TAG, "clampViewPositionVertical 建议值top:" + top + " mRange:" + mRange);
if (top > mRange) {
top = mRange;
} else if (top < 0) {
top = 0;
}
return top;
}
/**
* 当View的位置发生变化的时候,处理要做的事情(更新状态,伴随动画,重绘界面)
* 此时,View已经发生了位置的改变
*
* @param changedView 改变位置的View
* @param left 新的左边值
* @param top 新的上边值
* @param dx 水平方向的变化量
* @param dy 垂直方向的变化量
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
Log.d(TAG, "位置发生变化onViewPositionChanged:" + "新的左边值left: " + left + " 水平方向的变化量dx:" + dx
+ " 新的上边值top:" + top + " 垂直方向的变化量dy:" + dy);
super.onViewPositionChanged(changedView, left, top, dx, dy);
// 为了兼容低版本, 每次修改值之后, 进行重绘
invalidate();
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
//获取最新的left坐标
int newLeft = left;
if (changedView == mLeftContent) {
//如果滑动的是mLeftContent,则将其水平变化量dx传递给mMainContent,记录在newLeft中
newLeft = mMainContent.getLeft() + dx;
}
//矫正范围
if (newLeft > mRange) {
newLeft = mRange;
} else if (newLeft < 0) {
newLeft = 0;
}
//再次判断,限制mLeftContent的滑动
if (changedView == mLeftContent) {
//强制将mLeftContent的位置摆会原来的位置,这里通过layout方法传入左,上,右,下坐标来实现
//当然方法不限于这一种,例如还可以通过scrollTo(x,y)方法
mLeftContent.layout(0, 0, mWidth, mHeight);
//改变mMainContent的位置
mMainContent.layout(newLeft, 0, newLeft + mWidth, mHeight);
}
// 为了兼容低版本, 每次修改值之后, 进行重绘
invalidate();
}
/**
* 当被拖拽的View释放的时候回调,通常用于执行收尾的操作(例如执行动画)
* @param releasedChild 被释放的View
* @param xvel 水平方向的速度,向右释放为正值,向左为负值
* @param yvel 垂直方向的速度,向下释放为正值,向上为负值
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
Log.d(TAG, "View被释放onViewReleased:" + "释放时水平速度xvel:" + xvel + " 释放时垂直速度yvel:" + yvel);
super.onViewReleased(releasedChild, xvel, yvel);
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
Log.d(TAG, "View被释放onViewReleased:" + "释放时水平速度xvel:" + xvel + " 释放时垂直速度yvel:" + yvel);
super.onViewReleased(releasedChild, xvel, yvel);
if (xvel > 0 || (xvel == 0 && mMainContent.getLeft() > mRange / 2.0f)) {
//打开mLeftContent,即mMainContent的x=mRange
mMainContent.layout(mRange, 0, mRange + mWidth, mHeight);
} else {
//关闭mLeftContent,即mMainContent的x=0
mMainContent.layout(0, 0, mWidth, mHeight);
}
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
Log.d(TAG, "View被释放onViewReleased:" + "释放时水平速度xvel:" + xvel + " 释放时垂直速度yvel:" + yvel);
super.onViewReleased(releasedChild, xvel, yvel);
if (xvel > 0 || (xvel == 0 && mMainContent.getLeft() > mRange / 2.0f)) {
//打开mLeftContent,即mMainContent的x=mRange
if (dragHelper.smoothSlideViewTo(mMainContent, mRange, 0)) {
// 返回true代表还没有移动到指定位置, 需要刷新界面.
// 参数传this(child所在的ViewGroup)
ViewCompat.postInvalidateOnAnimation(DragLayout.this);
}
} else {
//关闭mLeftContent,即mMainContent的x=0
if (dragHelper.smoothSlideViewTo(mMainContent, 0, 0)) {
ViewCompat.postInvalidateOnAnimation(DragLayout.this);
}
}
@Override
public void computeScroll() {
super.computeScroll();
// 2. 持续平滑动画 (高频率调用)
if(dragHelper.continueSettling(true)){
// 如果返回true, 动画还需要继续执行
ViewCompat.postInvalidateOnAnimation(this);
}
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有