1. 程式人生 > >android Scroller簡單用法記錄

android Scroller簡單用法記錄

總體的流程:scroller儲存的是移動的資訊,這些資訊不針對任何的檢視,或者可以說是針對檢視樹。常用的最簡單的使用方法如下:
1、呼叫scroller的startScroll方法觸發滾動,但此時只是儲存了資訊,並沒有表明/指定哪些檢視需要滾動
2、startScroll呼叫後將要進行檢視重繪,此時可以通過重寫檢視樹中佈局檢視的相應方法實現滾動的效果。
3、當在檢視樹中的某個佈局中重寫了computeScroll方法,並在此方法中呼叫了scrollTo()方法,則該佈局下的直接子檢視(包含佈局檢視)將會按照scrollTo的要求進行移動;
4、 在沒有重寫computeScroll方法並在其內部呼叫scrollTo方法的佈局檢視下的子檢視相對於其佈局檢視的相對位置不變;
5、移動的細節是:當mScroller.computeScrollOffset()返回值為true時進行移動,

6、從startScroll中描述的當前參照座標向x、y方向位移,一邊移動一邊重新整理,在描述的滾動的週期時間結束後移動到指定位置並結束移動。

例項效果圖:



起始狀態

當點選如圖的第二塊灰色區域時,效果如下:


如圖,點選的是一個LinearLayout佈局元件,根佈局為垂直方向的ContentLinearLayout元件lay0,其子檢視為三個LinearLayout,分別為lay1,lay2,lay3;三個按鈕分別在為這三個線性佈局的子檢視,如圖。文字元件"hello scroller"屬於根檢視的直接子檢視,檢視樹如下:



當點選了上圖區域時,檢視樹重新整理,lay0的子檢視lay1,lay2,lay3,t按照ContentLayout中重寫的computeScroll()方法滾動,由於lay1,lay2也重寫了computeScroll方法,在它們佈局內的btn1,btn2由原來在父檢視的左上角部分向右下方滾動了一段距離。同理,由於lay3使用的是系統預設的LinearLayout,未進行滾動的自定義,所有btn3相對於lay3的位置未發生改變。

程式碼如下:

package com.cn.scrollerdemo;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;
public class TestScrollerActivity extends Activity {
	private static final String TAG = "TestScrollerActivity";
	LinearLayout lay1, lay2,lay3, 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);
		lay3=new LinearLayout(this);
		lay1.setBackgroundColor(this.getResources().getColor(
				android.R.color.darker_gray));
		lay2.setBackgroundColor(this.getResources().getColor(
				android.R.color.white));
		lay3.setBackgroundColor(this.getResources().getColor(
				android.R.color.darker_gray));
		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(
				200,
				LinearLayout.LayoutParams.WRAP_CONTENT);
		p1.weight = 1;
		lay0.addView(lay1, p1);
		
		
		LinearLayout.LayoutParams p2 = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.FILL_PARENT,
				LinearLayout.LayoutParams.WRAP_CONTENT);
		p2.weight = 1;
		lay0.addView(lay2, p2);
		
		LinearLayout.LayoutParams p3 = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.FILL_PARENT,
				LinearLayout.LayoutParams.WRAP_CONTENT);
		p3.weight = 1;
		lay0.addView(lay3, p2);
		
		MyButton btn1 = new MyButton(this);
		MyButton btn2 = new MyButton(this);
		MyButton btn3=new MyButton(this);
		btn1.setId(1);
		btn2.setId(2);
		btn1.setText("btn in layout1");
		btn2.setText("btn in layout2");
		btn3.setText("btn in layout3,無scrollTo");
		btn1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mScroller.startScroll(0, 0, -30, -30, 50);
			}
		});
		btn2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mScroller.startScroll(20, 20, -50, -50, 50);
			}
		});
		/**
		 * 為什麼當View做為lay0的子檢視時,設定lay0的監聽滾動時,此view沒有滾動的效果,
		 * 因為scrollerTo方法定義在MyLinearLayout中,也就是說只有MyLinearLayout下的檢視才能滾動
		 */
		lay1.addView(btn1);
		lay2.addView(btn2);
		lay3.addView(btn3);	//在未實現了computeScroll()方法的佈局中新增按鈕
		LinearLayout.LayoutParams p4 = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.WRAP_CONTENT,
				LinearLayout.LayoutParams.WRAP_CONTENT);
		p4.weight = 1;
		TextView t = new TextView(this);
		t.setText("hello scroller.");
		t.setLayoutParams(p4);
		lay0.addView(t, p4);

		lay0.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mScroller.startScroll(0, 0, -30, -30, 50);

				Log.e(TAG, "lay0--------------");
				// 重新整理介面
				lay0.invalidate();
			}

		});
	}

	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);
		}

		String flag;

		@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-----------:"
							+ mScroller.computeScrollOffset() + ":"
							+ mScroller.getCurrX());
			if (mScroller.computeScrollOffset())// 如果mScroller沒有呼叫startScroll,這裡將會返回false。
			{
				// 因為呼叫computeScroll函式的是MyLinearLayout例項,
				// 所以呼叫scrollTo移動的將是該例項的孩子,也就是MyButton例項............
				// scrollTo(mScroller.getCurrX(), 0);
				scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // scrollTo控制實際的移動,mScroller可看做一個儲存滾動資訊的一個結構體
				Log.d(TAG, "getCurrX = " + mScroller.getCurrX());
			}
		}
	}

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

		@Override
		protected void dispatchDraw(Canvas canvas) {
			Log.d("ContentLinearLayout", "contentview dispatchDraw");
			super.dispatchDraw(canvas);
		}
		// 當重寫後其所有直接子檢視都能夠移動,也就是說scrollTo只能控制其直接的子檢視,不能控制它子檢視是ViewGroup,這個ViewGroup的子檢視
		 public void computeScroll(){
		 if (mScroller.computeScrollOffset())//
		// 如果mScroller沒有呼叫startScroll,這裡將會返回false。
		 {
		 scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
		 //scrollTo控制實際的移動,mScroller可看做一個儲存滾動資訊的一個結構體
		 Log.d(TAG, "getCurrX = " + mScroller.getCurrX());
		 }
		 }
	}
}