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