在上一篇中介绍了View类的scrollTo和scrollBy两个方法,对这两个方法不太了解的朋友能够先看《自己定义View及ViewGroup

scrollTo和scrollBy尽管实现了视图的偏移,可是却没有更好的控制移动过程,移动是瞬间进行的。Scroller类就是为解决问题而设计的。

打开Scroller的源码,能够看到startScroll方法:

    /**
* Start scrolling by providing a starting point and the distance to travel.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
* @param duration Duration of the scroll in milliseconds.
*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}

能够看到,这种方法的作用是将View从一个起始位置通过给定移动偏移量和时间运行一段动画移动到目标位置。以下再来看一下View类提供的computeScroll方法

   /**
* 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() {
}

为了易于控制滑屏控制,Android框架提供了 computeScroll()方法去控制这个流程。在绘制View时,会在draw()过程调用该方法。为了实现偏移控制,一般自己定义View/ViewGroup都须要重载该方法 。

@Override
protected void dispatchDraw(Canvas canvas){
... for (int i = 0; i < count; i++) {
final View child = children[getChildDrawingOrder(count, i)];
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
more |= drawChild(canvas, child, drawingTime);
}
}
}
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
...
child.computeScroll();
...
}

以下我们来用《Android Scroller类的具体分析》给我们提供的代码分析一下

package com.example.testscrollto;

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; 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, -30, -30, 50);
}
});
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mScroller.startScroll(20, 20, -50, -50, 50);
}
});
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(TAG, 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实例
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(TAG, "contentview dispatchDraw");
super.dispatchDraw(canvas);
}
}
}


点击上面按钮,log输出例如以下:


当点击Button的时候背景发生了变化,就须要重绘,这时button调用invalidate方法请求重绘,这就是scroll动态效果的触发源,Scroller对象的实例是一个封装位置和速度的变量,startScroll()方法是对一些成员变量进行设置,设置的唯一效果是导致mScroller.computeScrollOffset()方法返回true.在button重绘的同一时候mScroller.startScroll()方法被调用,此时mScroller变量设置了有效的值。
接下来的过程就是View自上而下的绘制了。在绘制lay1的时候就会调用drawChild方法,这时候就会运行computeScrll()方法:

		public void computeScroll() {
Log.d(TAG, this.toString() + " computeScroll-----------");
if (mScroller.computeScrollOffset())// 假设mScroller没有调用startScroll,这里将会返回false。
{
// 由于调用computeScroll函数的是MyLinearLayout实例,
// 所以调用scrollTo移动的将是该实例的孩子,也就是MyButton实例
scrollTo(mScroller.getCurrX(), 0);
Log.d(TAG, "getCurrX = " + mScroller.getCurrX()); // 继续让系统重绘
getChildAt(0).invalidate();
}
}

直到startScroll中设置的时间到了,mScroller.computeScrollOffset()才返回false.




Android自己定义组件系列【2】——Scroller类的更多相关文章

  1. Android自己定义组件系列【7】——进阶实践(4)

    上一篇<Android自己定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识.这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpa ...

  2. Android自己定义组件系列【5】——进阶实践(2)

    上一篇<Android自己定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这 ...

  3. Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动

    在上一篇文章<Android自己定义组件系列[3]--自己定义ViewGroup实现側滑>中实现了仿Facebook和人人网的側滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布 ...

  4. Android自己定义组件系列【6】——进阶实践(3)

    上一篇<Android自己定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计 ...

  5. Android自己定义组件系列【3】——自己定义ViewGroup实现側滑

    有关自己定义ViewGroup的文章已经非常多了,我为什么写这篇文章,对于刚開始学习的人或者对自己定义组件比較生疏的朋友尽管能够拿来主义的用了,可是要一步一步的实现和了解当中的过程和原理才干真真脱离别 ...

  6. Android自己定义组件系列【1】——自己定义View及ViewGroup

    View类是ViewGroup的父类,ViewGroup具有View的全部特性.ViewGroup主要用来充当View的容器.将当中的View作为自己孩子,并对其进行管理.当然孩子也能够是ViewGr ...

  7. Android自己定义组件系列【5】——高级实践(1)

    在接下来的几篇文章将任老师的博文<您可以下拉PinnedHeaderExpandableListView实现>骤来具体实现.来学习一下大神的代码并记录一下. 原文出处:http://blo ...

  8. Android自己定义组件系列【9】——Canvas绘制折线图

    有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了非常多插件,可是非常多时候我们须要依据详细项目自己定义这些图表,这一篇文章我们一起来看看怎样在Android中使用Can ...

  9. Android自己定义组件系列【8】——面膜文字动画

    我们掩盖文字动画Flash中非经货共同体共同,由于Android应用程序开发人员做你想要做这个动画在应用程序中去?本文中,我们看的是如何自己的定义ImageView来实现让一张文字图片实现文字的遮罩闪 ...

随机推荐

  1. sql: oracle, for update和for update nowait的区别

    1. oracle for update和for update nowait的区别 http://www.cnblogs.com/quanweiru/archive/2012/11/09/276222 ...

  2. 用lambda表达式声明委托

    首先来分享一段代码: Func<int, int, int> addMethod = (int x, int y) => (x + y); 熟悉的人肯定知道这句话是什么意思,可是不熟 ...

  3. 基于visual Studio2013解决C语言竞赛题之1063分橘子

       题目 解决代码及点评 /* 功能:某桔农家共有2520只桔子, 父亲要将它们分给六个儿子,其分法如下: 父亲先将2520只桔子分给六个儿子, 然后说:"老大,把你分到的桔子 ...

  4. boost::asio async_write也不能保证一次发完所有数据 一

    你要是看过basic_stream_socket的文档,里面提到async_write_some不能保证将所有要发送的数据都发出去.并且提到如果想这样做,需要使用boost asio的async_wr ...

  5. HDU3709:Balanced Number(数位DP+记忆化DFS)

    Problem Description A balanced number is a non-negative integer that can be balanced if a pivot is p ...

  6. 【Linux】环境变量设置

    在Windows中环境变量设置是非常easy的事情.例如以下图.仅仅要右键我的电脑->高级系统设置->环境变量,选择Path之后,点击"编辑"就能够输入你要加入的内容. ...

  7. 谷歌浏览器訪问不了啦,oh shit!

    从这个礼拜開始,一直訪问不了谷歌.该死的,百度找的资料全然是牛头不正确马嘴 我也问了其它人.有的人也是打不开,蛋疼的 可是如今找到几种方法了,还真管用 第一种方法:加上ncr http://www.g ...

  8. WM_DRAWITEM与DrawItem()的讨论(自绘)

    http://blog.csdn.net/FlowShell/archive/2009/10/10/4648800.aspx 我在学习中经常遇到要重写DrawItem()的情况,但又有一个WM_DRA ...

  9. Solarized Colorscheme for IntelliJ IDEA

    Solarized Colorscheme for IntelliJ IDEA Original Solarized color scheme developed by Ethan Schoonove ...

  10. UVa11183 Teen Girl Squad, 最小树形图,朱刘算法

    Teen Girl Squad  Input: Standard Input Output: Standard Output You are part of a group of n teenage ...