参考网址:https://blog.csdn.net/itermeng/article/details/52159637?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
package com.example.lirui.draggroupdemo;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.NonNull;
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 com.nineoldandroids.view.ViewHelper;
/**
* Created by lirui on 2018/5/16.
* 自定义ViewGroup必须重写OnLayout方法。
*/
public class MyDragView extends ViewGroup {
private View mRedView;
private View mBlueView;
private ViewDragHelper viewDragHelper;
//初始化的时候调用
public MyDragView(Context context) {
this(context, null);
}
//xml布局的调用
public MyDragView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyDragView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化
init();
}
private void init() {
/*创建ViewDragHelper 作用:它主要用于处理ViewGroup中对子View的拖拽处理
它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的方式通知我们。所以我们需要做的只是用接收来的数据指定这些子View是否需要移动,移动多少等。
*/
viewDragHelper = ViewDragHelper.create(this, callBack);
}
private ViewDragHelper.Callback callBack = new ViewDragHelper.Callback() {
//尝试捕获拖拽的view
@Override
public boolean tryCaptureView(@NonNull View child, int pointerId) {
//返回要拖拽的view 确定那个view可以被拖拽
return child==mRedView||child==mBlueView;
}
//捕获拖拽的view
@Override
public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
//View的位置发生变化 多次被调用 可做伴随动画
@Override
public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
if(changedView==mRedView){
mBlueView.layout(mBlueView.getLeft()+dx,mBlueView.getTop()+dy,mBlueView.getRight()+dx,mBlueView.getBottom()+dy);
}else if(changedView==mBlueView){
mRedView.layout(mRedView.getLeft()+dx,mRedView.getTop()+dy,mRedView.getRight()+dx,mRedView.getBottom()+dy);
}
//执行动画
//1.计算view移动的百分比
float fraction = changedView.getLeft() * 1f / (getMeasuredWidth() - changedView.getMeasuredWidth());
Log.e("tag","fraction:"+fraction);
//2.执行一系列的伴随动画
executeAnim(fraction);
}
//View被释放,手离开了屏幕
@Override
public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int center = getMeasuredWidth() / 2 - releasedChild.getMeasuredWidth() / 2;
if(releasedChild.getLeft()//自动向左移动 Scroller(ScrollTo+ComputrScroll), 渐进式移动 , 属性动画
viewDragHelper.smoothSlideViewTo(releasedChild,0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragView.this);
}else{
//自动向右移动 注意调用动画必须重写computeScroll()方法
viewDragHelper.smoothSlideViewTo(releasedChild,getMeasuredWidth()-releasedChild.getMeasuredWidth(),releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragView.this);
}
}
//view横向拖拽范围
@Override
public int getViewHorizontalDragRange(@NonNull View child) {
return getMeasuredWidth()-mRedView.getMeasuredWidth();
}
//view纵向拖拽范围
@Override
public int getViewVerticalDragRange(@NonNull View child) {
return getMeasuredHeight()-mRedView.getMeasuredHeight();
}
//改变view的横向滑动位置
@Override
public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
//不让子view滑出屏幕外
if(left<0){
left=0;
}else if(left>getViewHorizontalDragRange(child)){
left=getViewHorizontalDragRange(child);
}
return left;
}
//改变View的纵向滑动位置
@Override
public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
//不让子view滑出屏幕外
if(top<0){
top=0;
}else if(top>getViewVerticalDragRange(child)){
top=getViewVerticalDragRange(child);
}
return top;
}
};
private void executeAnim(float fraction) {
//ViewHelper.setScaleX(mRedView, fraction + 1);
// ViewHelper.setScaleY(mRedView, fraction + 1);
// ViewHelper.setRotationY(mRedView, 720 * fraction);
//ViewHelper.setRotationY(mBlueView, 720 * fraction);
// ViewHelper.setTranslationX(mRedView,100*fraction);
// ViewHelper.setAlpha(mRedView, 1 - fraction);
ViewHelper.setRotationX(mRedView,720*fraction);
mRedView.setBackgroundColor((Integer) ColorUtil.evaluateColor(fraction, Color.RED,Color.BLACK));
setBackgroundColor((Integer) ColorUtil.evaluateColor(fraction, Color.YELLOW,Color.BLUE));
}
//xml文件执行完,紧接着执行该方法
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//获取两个view的实例 开始测量
mRedView = getChildAt(0);
mBlueView = getChildAt(1);
}
//测量的方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//测量布局的宽和高 开始摆放位置
measureChild(mRedView, widthMeasureSpec, heightMeasureSpec);
measureChild(mBlueView, widthMeasureSpec, heightMeasureSpec);
}
//确定子view的位置的方法
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//确定两个子view的位置
//如何摆放到父布局的中间位置 父布局的宽度的一般减去子view宽度的一半。
//int left=getPaddingLeft()+getMeasuredWidth()/2-mRedView.getMeasuredWidth()/2;
int left = getPaddingLeft();
int top = getPaddingTop();
mRedView.layout(left, top, left + mRedView.getMeasuredWidth(), top + mRedView.getMeasuredHeight());
mBlueView.layout(left, top + mRedView.getMeasuredHeight(), left + mRedView.getMeasuredWidth(), top + mRedView.getMeasuredHeight() + mBlueView.getMeasuredHeight());
}
//将ViewGroup的拦截事件交给DragHelper让其决定是否拦截
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
return viewDragHelper.shouldInterceptTouchEvent(event);
}
//将触摸事件交给DragHelper进行处理 通过这一步和上一步ViewGroup的子View就可以滑动了。
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
if(viewDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(MyDragView.this);
}
}
}