关于自定义ViewGroup的理解和ViewDraghelper的使用

来源:互联网 发布:哪有软件培训 编辑:程序博客网 时间:2024/05/16 11:41

在layout中创建一个activity_main.xml

<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity" >

    <mc.ViewGroup.MyDragViewGroup
        android:id="@+id/myDragViewGroup1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        >
        <TextView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="#f00" 
            android:padding="10dp"/>
        <TextView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:background="#00f" 
           />
    </mc.ViewGroup.MyDragViewGroup>

</LinearLayout>

新建一个Activity和一个自定义View :MainActivity  ,MyDragViewGroup



MainActivity:


MyDragViewGroup代码:

package mc.ViewGroup;


import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v4.widget.ViewDragHelper.Callback;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;
import android.widget.TextView;

public class MyDragViewGroup extends ViewGroup {

TextView redView,yelloView;
ViewDragHelper viewDragHelper;
Scroller scroller;

public MyDragViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyDragViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyDragViewGroup(Context context) {
super(context);
init();
}


private void init() {
viewDragHelper=ViewDragHelper.create(this, callback1);
scroller=new Scroller(getContext());
}


/**
* 读取完XML后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 习惯:在此方法中获得子View
redView = (TextView) getChildAt(0);
yelloView=(TextView) getChildAt(1);
}


/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);

Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);

int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);

// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));

//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);
}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);
}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);
}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理
return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {
return getMeasuredWidth()-child.getMeasuredWidth();
}

/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}

/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)

left=0;

if(left>getMeasuredWidth()-child.getMeasuredWidth())

left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/*//限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,getMeasuredWidth() - releasedChild.getMeasuredWidth(),releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};

public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};

/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



public MyDragViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyDragViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyDragViewGroup(Context context) {
super(context);
init();
}


private void init() {
viewDragHelper=ViewDragHelper.create(this, callback1);
scroller=new Scroller(getContext());
}


/**
* 读取完XML后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 习惯:在此方法中获得子View
redView = (TextView) getChildAt(0);
yelloView=(TextView) getChildAt(1);
}


/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


public MyDragViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyDragViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyDragViewGroup(Context context) {
super(context);
init();
}

private void init() {
viewDragHelper=ViewDragHelper.create(this, callback1);
scroller=new Scroller(getContext());
}


/**
* 读取完XML后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 习惯:在此方法中获得子View
redView = (TextView) getChildAt(0);
yelloView=(TextView) getChildAt(1);
}


/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



private void init() {
viewDragHelper=ViewDragHelper.create(this, callback1);
scroller=new Scroller(getContext());
}


/**
* 读取完XML后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 习惯:在此方法中获得子View
redView = (TextView) getChildAt(0);
yelloView=(TextView) getChildAt(1);
}


/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


private void init() {
viewDragHelper=ViewDragHelper.create(this, callback1);
scroller=new Scroller(getContext());
}

/**
* 读取完XML后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 习惯:在此方法中获得子View
redView = (TextView) getChildAt(0);
yelloView=(TextView) getChildAt(1);
}


/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 读取完XML后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 习惯:在此方法中获得子View
redView = (TextView) getChildAt(0);
yelloView=(TextView) getChildAt(1);
}


/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/**
* 读取完XML后回调
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 习惯:在此方法中获得子View
redView = (TextView) getChildAt(0);
yelloView=(TextView) getChildAt(1);
}

/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/**
* 测量OnMeasure
* (int widthMeasureSpec, int heightMeasureSpec)为父View测量并传过来的,且widthMeasureSpec属于一个MeasureSpec值
* 这样的话,MyDragViewGroup默认大小Size为在父控件中测量所得的值
*  利用setMeasuredDimension(480,300);//可以重新设置MyDragViewGroup的像素px大小
*  利用getHeight()可以获得当前View'的高度 可以利用 ,尽量使用getMeasuredHeight();
* int Heightsize=MeasureSpec.getSize(heightMeasureSpec); 
* int HeightMode=MeasureSpec.getMode(heightMeasureSpec); 获得当前VIewGroup的高宽和精确度模式

* 注:
* 作为一个ViewGroup,不在onMeasure中为其子控件测量的话,界面是无法显示子控件的,当然测量完成后还需要Layout摆放才可以显示
* 1.用 子View .measure(W, H);//W,H为 子View 的宽高的MeasureSpec值
* 2.measureChild(redView,widthMeasureSpec, heightMeasureSpec);//测量某个子View,widthMeasureSpec为父View的传值
* 3.measureChildren(widthMeasureSpec, heightMeasureSpec);//测量所有的子View
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/*
Log.i("widthMeasureSpec", "" + widthMeasureSpec);
Log.i("heightMeasureSpec", "" + heightMeasureSpec);
int Heightsize = MeasureSpec.getSize(heightMeasureSpec);
int HeightMode = MeasureSpec.getMode(heightMeasureSpec);
int Widthsize = MeasureSpec.getSize(widthMeasureSpec);
int WidthMode = MeasureSpec.getMode(widthMeasureSpec);

Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


Log.i("Heightsize", "" + Heightsize);
Log.i("HeightMode", "" + HeightMode);
Log.i("Widthsize", "" + Widthsize);
Log.i("WidthMode", "" + WidthMode);

int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


int ParentH = ((View) this.getParent()).getMeasuredHeight();// 父控件的高度
Log.i("ParentH", "" + ParentH);

// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


// 为子控件测量,定义其宽高
int W = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,
MeasureSpec.EXACTLY);
int H = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().height,
MeasureSpec.EXACTLY);
redView.measure(W, H);
yelloView.measure(MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().width,MeasureSpec.EXACTLY), 
MeasureSpec.makeMeasureSpec(yelloView.getLayoutParams().height,MeasureSpec.EXACTLY));

//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);

for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


//measureChild(redView,widthMeasureSpec, heightMeasureSpec);
//measureChild(yelloView,widthMeasureSpec, heightMeasureSpec);
for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);

}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


for(int i=0;i<getChildCount();i++){
measureChild(getChildAt(i),widthMeasureSpec, heightMeasureSpec);
}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


}
*/
measureChildren(widthMeasureSpec, heightMeasureSpec);


}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:




}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



}


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


}

/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();
int redViewpaddingL=redView.getPaddingLeft();
int redViewpaddingR=redView.getPaddingRight();
int redViewpaddingB=redView.getPaddingBottom();

int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/**
* 摆放onLayout
* 1.尽量使用getMeasuredWidth()而不是getWidth(),因为getMeasuredWidth为你测量所得的数据,而getWidth()为该控件View加载完毕后的数据,没加载之前为0
* 2.摆放时要考虑到padding问题

*/
@Override

protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int b) {

//摆放效果:让redView摆在横向居中,正下方为yelloView

int redViewpaddingT=redView.getPaddingTop();int redViewpaddingL=redView.getPaddingLeft();int redViewpaddingR=redView.getPaddingRight();int redViewpaddingB=redView.getPaddingBottom();
int redViewTop=redViewpaddingT+0;
int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;
int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;

redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


int redViewTop=redViewpaddingT+0;int redViewLeft=getMeasuredWidth()/2-redView.getMeasuredWidth()/2;int redViewRight=redView.getMeasuredWidth()+getMeasuredWidth()/2-redView.getMeasuredWidth()/2;int redViewBootom=redView.getMeasuredHeight()+redViewpaddingB;
redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);

int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


redView.layout(redViewLeft,redViewTop,redViewRight,redViewBootom);
int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;
int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;
int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;
yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);

}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


int yelloTop=yelloView.getPaddingTop()+0+redViewBootom;int yelloLeft=getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;int yelloRight=yelloView.getMeasuredWidth()+getMeasuredWidth()/2-yelloView.getMeasuredWidth()/2;int yelloBottom=yelloView.getPaddingBottom()+yelloView.getMeasuredHeight()+redViewBootom;yelloView.layout(yelloLeft, yelloTop, yelloRight, yelloBottom);
}


//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


}

//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



//判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


//判断是否拦截事件@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);return Isintercept;}
//将事件交给viewDragHelper处理
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


//将事件交给viewDragHelper处理@Overridepublic boolean onTouchEvent(MotionEvent event) {viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理

return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



return true;//消费掉事件
}

private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


return true;//消费掉事件}
private ViewDragHelper.Callback callback1=new Callback() {

/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


private ViewDragHelper.Callback callback1=new Callback() {
/**返回是否捕捉处理子View事件
* child: 当前触摸的子View return: true:就捕获并解析  false:不处理
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child==yelloView||child==redView;
}


/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/**返回是否捕捉处理子View事件* child: 当前触摸的子View return: true:就捕获并解析  false:不处理*/@Overridepublic boolean tryCaptureView(View child, int pointerId) {return child==yelloView||child==redView;}

/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* View被捕获时回调
* capturedChild:当前被捕获的View
*/
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
Log.i("Callback.onViewCaptured", "被捕捉");
}

/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** View被捕获时回调* capturedChild:当前被捕获的View*/@Overridepublic void onViewCaptured(View capturedChild, int activePointerId) {super.onViewCaptured(capturedChild, activePointerId);Log.i("Callback.onViewCaptured", "被捕捉");}
/**
* 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0
*/
@Override
public int getViewHorizontalDragRange(View child) {

return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0*/@Overridepublic int getViewHorizontalDragRange(View child) {
return getMeasuredWidth()-child.getMeasuredWidth();
}


/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


return getMeasuredWidth()-child.getMeasuredWidth();}

/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 获得View的拖拽垂直范围
*/
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight()-child.getMeasuredHeight();
}



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 获得View的拖拽垂直范围*/@Overridepublic int getViewVerticalDragRange(View child) {return getMeasuredHeight()-child.getMeasuredHeight();}


/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:




/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 控制child在水平方向的移动 
* left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx 
* dx:本次child水平方向移动的距离
* return: 表示你真正想让child的left变成的值
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//限制范围
if(left<0)
left=0;
if(left>getMeasuredWidth()-child.getMeasuredWidth())
left=getMeasuredWidth()-child.getMeasuredWidth();

return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 控制child在水平方向的移动 * left:表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx * dx:本次child水平方向移动的距离* return: 表示你真正想让child的left变成的值*/@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {//限制范围if(left<0)left=0;if(left>getMeasuredWidth()-child.getMeasuredWidth())left=getMeasuredWidth()-child.getMeasuredWidth();
return left;
}



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


return left;}


/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:




/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 控制child在垂直方向的移动 
* top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy 
* dy:本次child垂直方向移动的距离
* return: 表示你真正想让child的top变成的值
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
/* //限制范围
if (top < 0) {
top = 0;
} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {
top = getMeasuredHeight() - child.getMeasuredHeight();
}
*/

//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 控制child在垂直方向的移动 * top:表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy * dy:本次child垂直方向移动的距离* return: 表示你真正想让child的top变成的值*/@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {/*//限制范围if (top < 0) {top = 0;} else if (top > getMeasuredHeight() - child.getMeasuredHeight()) {top = getMeasuredHeight() - child.getMeasuredHeight();}*/
//伴随动画的限制范围
if(child==redView){
if(top<0)
top=0;
if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();
}
if(child==yelloView){
if(top<0+redView.getMeasuredHeight())
top=0+redView.getMeasuredHeight();
if(top>getMeasuredHeight()-child.getMeasuredHeight())
top=getMeasuredHeight()-child.getMeasuredHeight();
}

return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


//伴随动画的限制范围if(child==redView){if(top<0)top=0;if(top>getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight())top=getMeasuredHeight()-child.getMeasuredHeight()-yelloView.getMeasuredHeight();}if(child==yelloView){if(top<0+redView.getMeasuredHeight())top=0+redView.getMeasuredHeight();if(top>getMeasuredHeight()-child.getMeasuredHeight())top=getMeasuredHeight()-child.getMeasuredHeight();}
return top;
}

/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


return top;}
/**
* 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 
* changedView:位置改变的child
* left:child当前最新的left 
* top: child当前最新的top 
* dx: 本次水平移动的距离 
* dy: 本次垂直移动的距离
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
for(int i=0;i<getChildCount();i++){
if(changedView!=getChildAt(i)){
getChildAt(i).layout(getChildAt(i).getLeft()+dx,
getChildAt(i).getTop()+dy,
getChildAt(i).getRight()+dx,
getChildAt(i).getBottom()+dy);
}
}
}

/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 * changedView:位置改变的child* left:child当前最新的left * top: child当前最新的top * dx: 本次水平移动的距离 * dy: 本次垂直移动的距离*/@Overridepublic void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {super.onViewPositionChanged(changedView, left, top, dx, dy);for(int i=0;i<getChildCount();i++){if(changedView!=getChildAt(i)){getChildAt(i).layout(getChildAt(i).getLeft()+dx,getChildAt(i).getTop()+dy,getChildAt(i).getRight()+dx,getChildAt(i).getBottom()+dy);}}}
/**
* 手指抬起的执行该方法,
*  releasedChild:当前抬起的view 
*  xvel: x方向的移动的速度 正:向右移动, 负:向左移动
*  yvel: y方向移动的速度
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int centerLeft = getMeasuredWidth() / 2
- releasedChild.getMeasuredWidth() / 2;
if (releasedChild.getLeft() < centerLeft) {
// 在左半边,应该向左缓慢移动
//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局

/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 手指抬起的执行该方法,*  releasedChild:当前抬起的view *  xvel: x方向的移动的速度 正:向右移动, 负:向左移动*  yvel: y方向移动的速度*/@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {super.onViewReleased(releasedChild, xvel, yvel);int centerLeft = getMeasuredWidth() / 2- releasedChild.getMeasuredWidth() / 2;if (releasedChild.getLeft() < centerLeft) {// 在左半边,应该向左缓慢移动//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新整个个布局
/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);
invalidate();*/

} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*scroller.startScroll(releasedChild.getLeft(), releasedChild.getTop(),-releasedChild.getLeft(), 0,1000);invalidate();*/
} else {
// 在右半边,应该向右缓慢移动
viewDragHelper.smoothSlideViewTo(releasedChild,
getMeasuredWidth() - releasedChild.getMeasuredWidth(),
releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


} else {// 在右半边,应该向右缓慢移动viewDragHelper.smoothSlideViewTo(releasedChild,getMeasuredWidth() - releasedChild.getMeasuredWidth(),releasedChild.getTop());ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);
invalidate();*/
}
Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());
}

};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*scroller.startScroll(0,0, getMeasuredWidth()-releasedChild.getRight(),0,1000);invalidate();*/}Log.i("AAA", “Left:”+releasedChild.getLeft()+"   Top:"+releasedChild.getTop()+" getMeasuredWidth() "+releasedChild.getRight());}
};





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


};




public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:






public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:





public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:




public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}

/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


public void computeScroll() {if (viewDragHelper.continueSettling(true)) {ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);}
/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),0);
invalidate();
Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());
}*/
};






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。scrollTo(scroller.getCurrX(),0);invalidate();Log.i("SSS",""+scroller.getCurrX()+"  "+scroller.getCurrY());}*/};





/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:







/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:






/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:





/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:




/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 笔记
* * 一.View移动的相关方法总结:
  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:
    view.layout(l,t,r,b);
view.offsetLeftAndRight(offset);//同时改变left和right
view.offsetTopAndBottom(offset);//同时改变top和bottom
  2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;
    scrollTo(x,y);
scrollBy(xOffset,yOffset);
  3.通过改变Canvas绘制的位置来移动View的内容:
    canvas.drawBitmap(bitmap, left, top, paint)
    
    
二.使用ViewDragHelper来处理移动
  1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中
  2.它主要用于处理ViewGroup中对子View的拖拽处理
  3.它是Google在2013年开发者大会提出的 
  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的
    方式告诉我们;只需要我们指定是否需要移动,移动多少等;  
  5.本质是对触摸事件的解析类;

三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 笔记* * 一.View移动的相关方法总结:  1.通过改变view在父View的layout位置来移动,但是只能移动指定的View:   view.layout(l,t,r,b);view.offsetLeftAndRight(offset);//同时改变left和rightview.offsetTopAndBottom(offset);//同时改变top和bottom 2.通过改变scrollX和scrollY来移动,但是可以移动所有的子View;    scrollTo(x,y);scrollBy(xOffset,yOffset);  3.通过改变Canvas绘制的位置来移动View的内容:   canvas.drawBitmap(bitmap, left, top, paint)        二.使用ViewDragHelper来处理移动 1.ViewDragHelper在高版本的v4包(android4.4以上的v4)中  2.它主要用于处理ViewGroup中对子View的拖拽处理  3.它是Google在2013年开发者大会提出的  4.它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的   方式告诉我们;只需要我们指定是否需要移动,移动多少等;    5.本质是对触摸事件的解析类;
三.getHeight和getMeasuredHeight的区别:
  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值;
  getHeight:只有view执行完layout才能获取到值;
  
四.
        在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的
        布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;


 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


三.getHeight和getMeasuredHeight的区别:  getMeasuredHeight:只要view执行完onMeasure方法就能够获取到值; getHeight:只有view执行完layout才能获取到值;  四.       在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的       布局(比如FrameLayout),目的是为了让已有的布局帮我们实行onMeasure;

 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



 */
void A1(){

}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


 */void A1(){
}



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


}


/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:




/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:



/**
* 关于Srcoller滑动处理器
* 作用:让控件自动缓慢滑动到目的地
* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]

* 1.scroller.startScroll(startX,startY,dx,dy);
* startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动
* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动
* dx 水平方向滑动的距离,正值会使滚动向左滚动
* dy 垂直方向滑动的距离,正值会使滚动向上滚动
* 2.重写 computeScroll() {}函数
* public void computeScroll() {
if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();//刷新界面
}
};

*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


/*** 关于Srcoller滑动处理器* 作用:让控件自动缓慢滑动到目的地* 注:是通过ScrollTo()实现,即通过目的坐标滑动,是滑动整个父View,从而改变显示位置。[ScrollBy()则是通过偏移量滑动,也是滑动整个父View]* * 1.scroller.startScroll(startX,startY,dx,dy);*startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动* startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动* dx 水平方向滑动的距离,正值会使滚动向左滚动*dy 垂直方向滑动的距离,正值会使滚动向上滚动* 2.重写computeScroll() {}函数* public void computeScroll() {if(scroller.computeScrollOffset()){//如果mScroller没有调用startScroll,这里将会返回false。scrollTo(scroller.getCurrX(),scroller.getCurrY());invalidate();//刷新界面}};
*
*其原理:
* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量
* 再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置
*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)
*  
*  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处
*/

void A2(){}

/**
* 关于ViewDragHelper笔记:
* 用法一:实现View的拖拽移动
* 1.定义一个ViewDragHelper对象
* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);
* 2.定义回调Callback对象
* private ViewDragHelper.Callback callback1=new Callback() {
* 。。。。。(重写其方法)
* }
* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件
* //判断是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);
return Isintercept;
}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理
* @Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理


return true;//消费掉事件
}
*
*用法二:实现View的Scroll效果
*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()
viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局
*2.重写computeScroll()
* public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);
}
};
*/
void A3(){};


}

效果图:


**其原理:* 先通过StartScroll(。。。)获得起始坐标和需要偏移的坐标量*再将偏移量用时间分割,然后得到每个时间间隔搜需要到达的位置*  再通过ScrollTo(..)到达指定位置(由左上角的坐标为原点进行偏移)*  *  当偏移的位置超出View的边界大小时,动画结束后会弹回边界处*/

void A2(){}

/**

* 关于ViewDragHelper笔记:

* 用法一:实现View的拖拽移动

* 1.定义一个ViewDragHelper对象

* ViewDragHelper viewDragHelper=ViewDragHelper.create(this, callback1);

* 2.定义回调Callback对象

* private ViewDragHelper.Callback callback1=new Callback() {

* 。。。。。(重写其方法)

* }

* 3.在 onInterceptTouchEvent(MotionEvent ev)中判断是否拦截事件

* //判断是否拦截事件

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

boolean Isintercept=viewDragHelper.shouldInterceptTouchEvent(ev);

return Isintercept;

}

* 4.在onTouchEvent(。。)中给viewDragHelper赋予事件处理

* @Override

public boolean onTouchEvent(MotionEvent event) {

viewDragHelper.processTouchEvent(event);//将事件交给viewDragHelp处理



return true;//消费掉事件

}

*

*用法二:实现View的Scroll效果

*1.//内部封装了Srcoller,不需要自己实现,调用smoothSlideViewTo()

viewDragHelper.smoothSlideViewTo(releasedChild, 0,releasedChild.getTop());

ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);//刷新真个布局

*2.重写computeScroll()

* public void computeScroll() {

if (viewDragHelper.continueSettling(true)) {

ViewCompat.postInvalidateOnAnimation(MyDragViewGroup.this);

}

};

*/

void A3(){};


}

效果图:


0 0
原创粉丝点击