版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32113133/article/details/65628946
Scroller 类在滚动过程的的几个主要作用如下:
启动滚动动作;
根据ᨀ供的滚动目标位置和持续时间计算出中间的过渡位置;
判断滚动是否结束;
介入 View 或 ViewGroup 的重绘流程,从而形成滚动动画。
Scroller涉及到的方法:
public Scroller(Contextcontext)
public Scroller(Contextcontext, Interpolatorinterpolator)
public Scroller(Contextcontext, Interpolatorinterpolator, booleanflywheel)
构造方法, interpolator 指 定 插 速器,如果没有指定,默认插速器为ViscousFluidInterpolator,flywheel 参数为 true 可以ᨀ供类似“飞轮”的行为;
public final void setFriction(floatfriction)
设置一个摩擦系数,默认为 0.015f,摩擦系数决定惯性滑行的距离;
public final int getStartX()
返回起始 x 坐标值;
public final int getStartY()
返回起始 y 坐标值;
public final int getFinalX()
返回结束 x 坐标值;
public final int getFinalY()
返回结束 y 坐标值;
public final int getCurrX()
返回滚动过程中的 x 坐标值,滚动时会ᨀ供 startX(起始)和 finalX(结束),currX 根据这两个值计算而来;
public final int getCurrY()
返回滚动过程中的 y 坐标值,滚动时会ᨀ供 startY(起始)和 finalY(结束),currY 根据这两个值计算而来;
public booleancomputeScrollOffset()
计算滚动偏移量,必调方法之一。主要负责计算 currX 和 currY 两个值,其返回值为true 表示滚动尚未完成,为 false 表示滚动已结束;
public void startScroll(int startX,int startY,int dx,int dy)
public void startScroll(int startX,int startY,int dx,int dy,int duration)
启动滚动行为,startX 和 startY 表示起始位置,dx、dy 表示要滚动的 x、y 方向的距离,duration 表示持续时间,默认时间为 250 毫秒;
public final boolean isFinished()
判断滚动是否已结束,返回 true 表示已结束;
public final void forceFinished(booleanfinished)
强制结束滚动,currX、currY 即为当前坐标;
public void abortAnimation()
与 forceFinished 功用类似,停止滚动,但 currX、currY 设置为终点坐标;
public void extendDuration(int extend)
延长滚动时间;
public int timePassed()
返回滚动已耗费的时间,单位为毫秒;
public void setFinalX(int newX)
设置终止位置的 x 坐标,可能需要调用 extendDuration()延长或缩短动画时间;
public void setFinalY(int newY)
设置终止位置的 y 坐标,可能需要调用 extendDuration()延长或缩短动画时间。
上面的方法中,常用的主要有 startScroll()、computeScrollOffset()、getCurrX()、getCurrY()和
activity_main:
MainActivity:
1) 调用 scroller 的 startScroll()方法定义滚动的起始位置和滚动的距离;
2) 通过 invalidate()或 postInvalidate()方法刷新,调用 draw(Canvas)方法重绘组件;
3) 调用 computeScroll()计算下一个位置的坐标;
4) 再次调用 invalidate()或 postInvalidate()方法刷新重绘;
5) 判断 computeScroll()方法的返回值,如果为 false 表示结束滚动,为 true 表示继续滚动。
上面的步骤其实构建了一个方法调用循环:1) ->2) ->3) ->4) ->5) ->3) ->4) ->5)……,3) ->4) ->5)就是一个循环,该循环用于不断计算下一个位置,并通过重绘移动到该位置,这样就产生了动画效果。
另外,我们还定义了两个用来与外部交互的方法:start()和 abort()。start()方法用于启动滚动动作,执行了 scroller.startScroll(this.getScrollX(), this.getScrollY(), - 900, 0,10000)语句,其中参数this.getScrollX()和 this.getScrollY()是容器内容的初始位置,x 方向向右移动 900 个单位距离(为负才表示向右),y 方向不变,也就是水平向右移动,为了更好的查看动画过程,将滚动持续时间设为 10 秒。和上面一样,就算调用了 startScroll()方法,也需要调用 invadate()或 postInvalidate()方
法进行重绘。在 abort()方法中调用了 scroller.abortAnimation()方法,用来停止滚动。
启动滚动动作;
根据ᨀ供的滚动目标位置和持续时间计算出中间的过渡位置;
判断滚动是否结束;
介入 View 或 ViewGroup 的重绘流程,从而形成滚动动画。
Scroller涉及到的方法:
public Scroller(Contextcontext)
public Scroller(Contextcontext, Interpolatorinterpolator)
public Scroller(Contextcontext, Interpolatorinterpolator, booleanflywheel)
构造方法, interpolator 指 定 插 速器,如果没有指定,默认插速器为ViscousFluidInterpolator,flywheel 参数为 true 可以ᨀ供类似“飞轮”的行为;
public final void setFriction(floatfriction)
设置一个摩擦系数,默认为 0.015f,摩擦系数决定惯性滑行的距离;
public final int getStartX()
返回起始 x 坐标值;
public final int getStartY()
返回起始 y 坐标值;
public final int getFinalX()
返回结束 x 坐标值;
public final int getFinalY()
返回结束 y 坐标值;
public final int getCurrX()
返回滚动过程中的 x 坐标值,滚动时会ᨀ供 startX(起始)和 finalX(结束),currX 根据这两个值计算而来;
public final int getCurrY()
返回滚动过程中的 y 坐标值,滚动时会ᨀ供 startY(起始)和 finalY(结束),currY 根据这两个值计算而来;
public booleancomputeScrollOffset()
计算滚动偏移量,必调方法之一。主要负责计算 currX 和 currY 两个值,其返回值为true 表示滚动尚未完成,为 false 表示滚动已结束;
public void startScroll(int startX,int startY,int dx,int dy)
public void startScroll(int startX,int startY,int dx,int dy,int duration)
启动滚动行为,startX 和 startY 表示起始位置,dx、dy 表示要滚动的 x、y 方向的距离,duration 表示持续时间,默认时间为 250 毫秒;
public final boolean isFinished()
判断滚动是否已结束,返回 true 表示已结束;
public final void forceFinished(booleanfinished)
强制结束滚动,currX、currY 即为当前坐标;
public void abortAnimation()
与 forceFinished 功用类似,停止滚动,但 currX、currY 设置为终点坐标;
public void extendDuration(int extend)
延长滚动时间;
public int timePassed()
返回滚动已耗费的时间,单位为毫秒;
public void setFinalX(int newX)
设置终止位置的 x 坐标,可能需要调用 extendDuration()延长或缩短动画时间;
public void setFinalY(int newY)
设置终止位置的 y 坐标,可能需要调用 extendDuration()延长或缩短动画时间。
上面的方法中,常用的主要有 startScroll()、computeScrollOffset()、getCurrX()、getCurrY()和
abortAnimation()等几个方法。
ScrollerViewGroup:
public class ScrollerViewGroup extends ViewGroup{
private Scroller scroller;
private Button customButtom;
private LayoutParams layoutParams;
public ScrollerViewGroup(Context context) {
super(context);
}
public ScrollerViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ScrollerViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void init(Context context){
scroller = new Scroller(context);//实例化Scroller
customButtom = new Button(context);
layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
customButtom.setText("自定义Button");
addView(customButtom,layoutParams);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//为子View设置位置
customButtom.layout(100,100,customButtom.getMeasuredWidth()+100,customButtom.getMeasuredHeight()+100);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getSize(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//MeasureSpec封装了父布局传递给子布局的布局要求
//下面就是父布局传递给ScrollerViewGroup的布局要求
if(widthMode==MeasureSpec.AT_MOST || heightMode==MeasureSpec.AT_MOST){
//ScrollerViewGroup的宽或者高是不能设置为包裹
throw new IllegalStateException("The ViewGroup must is match_parent or gudingzhi");
}
//测量子View宽高
measureChildren(widthMeasureSpec,heightMeasureSpec);
//测量自己宽高
setMeasuredDimension(widthSize,heightSize);
}
@Override
public void computeScroll() {
if(scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(),scroller.getCurrY());
postInvalidate();
scroller.getCurrX();
scroller.getStartX();
scroller.getFinalX();
Log.i("log","getCurrX:"+ scroller.getCurrX()+",getStartX"+scroller.getStartX()+",getFinalX"+scroller.getFinalX());
}
}
public void start(){
scroller.startScroll(getScrollX(),getScrollY(),-200,0,10000);
postInvalidate();//重绘将执行computeScroll
}
public void abort(){
scroller.abortAnimation();//停止滚动动画
}
}
activity_main:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.user.myapplication4.ScrollerViewGroup
android:layout_width="match_parent"
android:id="@+id/scroll_layout"
android:layout_height="100dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<Button
android:id="@+id/start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="开始滚动"/>
<Button
android:id="@+id/abort"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/holo_blue_bright"
android:text="停止滚动"/>
</LinearLayout>
</LinearLayout>
MainActivity:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ScrollerViewGroup scroll_layout = (ScrollerViewGroup) findViewById(R.id.scroll_layout);
Button start = (Button) findViewById(R.id.start);
Button abort = (Button) findViewById(R.id.abort);
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scroll_layout.start();
}
});
abort.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scroll_layout.abort();
}
});
}
}
平滑滚动的基本工作流程:
1) 调用 scroller 的 startScroll()方法定义滚动的起始位置和滚动的距离;
2) 通过 invalidate()或 postInvalidate()方法刷新,调用 draw(Canvas)方法重绘组件;
3) 调用 computeScroll()计算下一个位置的坐标;
4) 再次调用 invalidate()或 postInvalidate()方法刷新重绘;
5) 判断 computeScroll()方法的返回值,如果为 false 表示结束滚动,为 true 表示继续滚动。
上面的步骤其实构建了一个方法调用循环:1) ->2) ->3) ->4) ->5) ->3) ->4) ->5)……,3) ->4) ->5)就是一个循环,该循环用于不断计算下一个位置,并通过重绘移动到该位置,这样就产生了动画效果。
另外,我们还定义了两个用来与外部交互的方法:start()和 abort()。start()方法用于启动滚动动作,执行了 scroller.startScroll(this.getScrollX(), this.getScrollY(), - 900, 0,10000)语句,其中参数this.getScrollX()和 this.getScrollY()是容器内容的初始位置,x 方向向右移动 900 个单位距离(为负才表示向右),y 方向不变,也就是水平向右移动,为了更好的查看动画过程,将滚动持续时间设为 10 秒。和上面一样,就算调用了 startScroll()方法,也需要调用 invadate()或 postInvalidate()方
法进行重绘。在 abort()方法中调用了 scroller.abortAnimation()方法,用来停止滚动。