Android自己定义组件系列【2】——Scroller类
在上一篇中介绍了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类的更多相关文章
- Android自己定义组件系列【7】——进阶实践(4)
上一篇<Android自己定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识.这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpa ...
- Android自己定义组件系列【5】——进阶实践(2)
上一篇<Android自己定义组件系列[5]--进阶实践(1)>中对任老师的<可下拉的PinnedHeaderExpandableListView的实现>前一部分进行了实现,这 ...
- Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动
在上一篇文章<Android自己定义组件系列[3]--自己定义ViewGroup实现側滑>中实现了仿Facebook和人人网的側滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布 ...
- Android自己定义组件系列【6】——进阶实践(3)
上一篇<Android自己定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计 ...
- Android自己定义组件系列【3】——自己定义ViewGroup实现側滑
有关自己定义ViewGroup的文章已经非常多了,我为什么写这篇文章,对于刚開始学习的人或者对自己定义组件比較生疏的朋友尽管能够拿来主义的用了,可是要一步一步的实现和了解当中的过程和原理才干真真脱离别 ...
- Android自己定义组件系列【1】——自己定义View及ViewGroup
View类是ViewGroup的父类,ViewGroup具有View的全部特性.ViewGroup主要用来充当View的容器.将当中的View作为自己孩子,并对其进行管理.当然孩子也能够是ViewGr ...
- Android自己定义组件系列【5】——高级实践(1)
在接下来的几篇文章将任老师的博文<您可以下拉PinnedHeaderExpandableListView实现>骤来具体实现.来学习一下大神的代码并记录一下. 原文出处:http://blo ...
- Android自己定义组件系列【9】——Canvas绘制折线图
有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了非常多插件,可是非常多时候我们须要依据详细项目自己定义这些图表,这一篇文章我们一起来看看怎样在Android中使用Can ...
- Android自己定义组件系列【8】——面膜文字动画
我们掩盖文字动画Flash中非经货共同体共同,由于Android应用程序开发人员做你想要做这个动画在应用程序中去?本文中,我们看的是如何自己的定义ImageView来实现让一张文字图片实现文字的遮罩闪 ...
随机推荐
- Linux经常使用命令(十二) - less
less 工具也是对文件或其他输出进行分页显示的工具.应该说是linux正统查看文件内容的工具.功能极其强大. less 的使用方法比起 more 更加的有弹性.使用了 less 时.更easy用来查 ...
- Hadoop SequenceFile
SequenceFile格式: 每一个SequenceFile都包含一个“头”(header).Header包含了以下几部分. 1.SEQ三个字母的byte数组 2.Version number的by ...
- js点击button按钮跳转到另一个新页面
点击按钮怎么跳转到另外一个页面呢?我们在网站制作中可能是需要的,因为有时我们需要做这样的效果,尤其是将按钮做成一个图片,而点击图片要跳转到新的页面时,怎么做到呢? 这样的效果可以:onclick=&q ...
- Winfrom设置DataGridView单元格获得焦点(DataGridView - CurrentCell)
设置DataGridView单元格获得焦点 this.dgv_prescription.BeginEdit(true);
- 基于visual Studio2013解决C语言竞赛题之1079狼羊过河
题目 解决代码及点评 /************************************************************************/ /* ...
- <转载>使用css让大图片不超过网页宽度
让大图片不超过网页宽度,让图片不撑破通过CSS样式设置的DIV宽度! 接下来,我们来介绍下网站在开发DIV+CSS的时候会遇到一个问题,在发布一个大图片的时候因为图片过宽会撑破自己设置的div宽度的问 ...
- WPF程序长时间无人操作
在软件开发中为了安全性,特别是那些需要用到用户名和密码登录服务端的程序,常常考虑长期无人操作,程序自动跳转到用户登录界面. 判断程序是否长时间无人操作,有两个依据,第一个是鼠标长时间不动,第二个是鼠标 ...
- C 语言资源大全中文版
C 语言资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-c 是 koz.ross 发起维护的 C 语言资源列表,内容包括了: ...
- javascript addEventListener方法
addEventListener是一个侦听事件并处理相应的函数. DOM方法 addEventListener() 和 removeEventListener()是用来分配和删除事件的函数. 这两个方 ...
- jeecg智能开发平台参与-2013年度中国优秀开源项目评比
JEECG正在参与<2013年度中国十大优秀开源项目> 评比,如果大家觉得JEECG还不错, 请投出你宝贵的一票,给我们以支持吧!!! [目前排名第8位] https://code.csd ...