总结Scroller ScrollTo ScrollBy

这两天看了两篇文章

http://blog.csdn.net/vipzjyno1/article/details/24577023讲ScrollTo和ScrollBy的用法,

http://blog.csdn.net/gemmem/article/details/7321910讲Scroller类的用法

自己总结一下,ScrollTo是移动到哪,ScrollBy是移动了多少距离,

如果传入的x和y(这里的x和y都是px,可以用dp2px转下)是一样的话,ScrollTo重复调用只能移动一次到,而ScrollBy重复调用能移动很多次,这跟这两个方法的android源码实现有关,具体看上面网址。

而ScrollTo移动的其实不是这个View移动,而是这个View里面的内容移动,甚至乎这个View可以不是ViewGroup的子类,可以是一个Button,这里是很奇怪的现象,我代码测试了下Button里面的字移动了,而这个button没移动

测试代码就是用的上面Scroller网址的代码修改了下:

public class MainActivity extends Activity {
	private static final String TAG = "TestScrollerActivity";
	LinearLayout lay1, lay2, lay0;
	private Scroller mScroller;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mScroller = new Scroller(this);
		lay1 = new MyLinearLayout(this);
		lay2 = new MyLinearLayout(this);

		lay1.setBackgroundColor(this.getResources().getColor(
				android.R.color.darker_gray));
		lay2.setBackgroundColor(this.getResources().getColor(
				android.R.color.white));
		lay0 = new ContentLinearLayout(this);
		lay0.setOrientation(LinearLayout.VERTICAL);
		LinearLayout.LayoutParams p0 = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.FILL_PARENT,
				LinearLayout.LayoutParams.FILL_PARENT);
		this.setContentView(lay0, p0);

		LinearLayout.LayoutParams p1 = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.FILL_PARENT,
				LinearLayout.LayoutParams.FILL_PARENT);
		p1.weight = 1;
		lay0.addView(lay1, p1);
		LinearLayout.LayoutParams p2 = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.FILL_PARENT,
				LinearLayout.LayoutParams.FILL_PARENT);
		p2.weight = 1;
		lay0.addView(lay2, p2);
		MyButton btn1 = new MyButton(this);
		MyButton btn2 = new MyButton(this);
		btn1.setText("btn in layout1");
		btn2.setText("btn in layout2");
		btn1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mScroller.startScroll(0, 0, -DensityUtil.dp2px(MainActivity.this, 30), -DensityUtil.dp2px(MainActivity.this, 30), 50);
				lay1.invalidate();
			}
		});
		btn2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mScroller.startScroll(0, 0, -DensityUtil.dp2px(MainActivity.this, 100), -DensityUtil.dp2px(MainActivity.this, 100), 50);
				lay2.invalidate();
			}
		});
		lay1.addView(btn1);
		lay2.addView(btn2);
	}

	class MyButton extends Button {
		public MyButton(Context ctx) {
			super(ctx);
		}

		@Override
		protected void onDraw(Canvas canvas) {
			super.onDraw(canvas);
			Log.d("MyButton", this.toString() + " onDraw------");
		}
	}

	class MyLinearLayout extends LinearLayout {
		public MyLinearLayout(Context ctx) {
			super(ctx);
		}

		@Override
		/**
		 * Called by a parent to request that a child update its values for mScrollX
		 * and mScrollY if necessary. This will typically be done if the child is
		 * animating a scroll using a {@link android.widget.Scroller Scroller}
		 * object.
		 */
		public void computeScroll() {
			Log.d(TAG, this.toString() + " computeScroll-----------");
			if (mScroller.computeScrollOffset())// 如果mScroller没有调用startScroll,这里将会返回false。
			{
				// 因为调用computeScroll函数的是MyLinearLayout实例,
				// 所以调用scrollTo移动的将是该实例的孩子,也就是MyButton实例
				getChildAt(0).scrollTo(mScroller.getCurrX(), 0);
				Log.d(TAG, "getCurrX = " + mScroller.getCurrX());

				// 继续让系统重绘
				getChildAt(0).invalidate();
			}
		}
	}

	class ContentLinearLayout extends LinearLayout {
		public ContentLinearLayout(Context ctx) {
			super(ctx);
		}

		@Override
		protected void dispatchDraw(Canvas canvas) {
			Log.d("ContentLinearLayout", "contentview dispatchDraw");
			super.dispatchDraw(canvas);
		}
	}
}

首先每个按钮点击的时候都是按钮的父View手动调用invalidate,父View的invalidate会导致父View重新draw一遍,这时就会调用父类重写的computeScroll方法,这个时候我们之前设置的Scroller值就去计算有没有scroll完成computeScrollOffset(),我在判断里面使用getChildAt(0).scrollTo(mScroller.getCurrX(), 0);getChildAt(0).invalidate();(其实这里第二句可以不需要,因为scrollTo就会重画),我们这里 getChildAt(0)可以肯定的是得到的是这个自定义layout里的Button对象,但是这个Button.scrollTo(mScroller.getCurrX(), 0)移动的竟然是Button里面的字,这个Button还在原地啊,是的没错,所以说ScrollTo移动的是View里面内容的位置,不管这个View是ViewGroup类的子类,还是android.weidget下面的Button,ImageView,TextView等,其实移动的都是这个View里面的内容的位置,ScrollTo并没有真正移动这个View,而只是把这个View显示在界面上的区域给扩大了,如果这个View是wrap或者固定的宽高,如果ScrollTo超过了这个View的区域,然后我给这个View提前设置了onclick事件,发现即使这个View的内容不见了(因为被ScrollTo到超出view的范围去了),但是onclick事件还能触发,也就是说这个View的左上角位置没变,但是这个View里面的内容被移动到了原先区域的外面去了。

突然想起还个没解释,就是为什么自定义的RelativeLayout里面的Button移动了,这个Button点击响应,而不是点击Button移动前的位置区域响应呢,答案很简单,还是ScrollTo改变的是view的内容位置,而并不是这个View。如何解释呢,就是这里这个自定义的RelativeLayout就是这个View,然后改变了内容就是Button,所以Button响应点击事件,而不是Button移动前的区域响应,

而像Button,ImageView这些View执行ScrollTo之后只是为了移动这个Button和ImageView,而把原本用来显示Button和ImageView的区域给扩大了,导致Button和ImageView里的内容移动,而不是这个区域移动,button的区域就是默认的android按钮背景,Imageview如果也设了背景的话也是,只是这个src图移动,背景不动,TextView也是这样。

哦了~~~这样就能解释我今天遇到的迷惑了,文字描述的不够好,见谅,代码贴太麻烦了。

你可能感兴趣的:(总结Scroller ScrollTo ScrollBy)