日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

android 最新消息滚动,Android 滚动操作Scroller类详解

發(fā)布時(shí)間:2023/12/19 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 最新消息滚动,Android 滚动操作Scroller类详解 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Scroller這個(gè)類(lèi)理解起來(lái)有一定的困難,剛開(kāi)始接觸Scroller類(lèi)的程序員可能無(wú)法理解Scroller和View系統(tǒng)是怎么樣聯(lián)系起來(lái)的。我經(jīng)過(guò)自己的學(xué)習(xí)和實(shí)踐,對(duì)Scroller的用法和工作原理有了一定的理解,在這里和大家分享一下,希望大家多多指教。

首先從源碼開(kāi)始分析:

View.java/**

* 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 [email?protected] android.widget.Scroller Scroller}

* object.

*/

public void computeScroll()

{

}

computeScroll是一個(gè)空函數(shù),很明顯我們需要去實(shí)現(xiàn)它,至于做什么,就由我們自己來(lái)決定了。

因?yàn)閂iew的子類(lèi)很多,在下面的例子中,我會(huì)在一個(gè)自定義的類(lèi)MyLinearLayout中去實(shí)現(xiàn)它。

ViewGroup.java@Override

protected void dispatchDraw(Canvas canvas) {

.......

.......

.......

.......

for (int i = 0; i < count; i++) {

final View child = children[i];

if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)

{

more |= drawChild(canvas, child, drawingTime);

}

.......

.......

.......

}

從dispatchDraw函數(shù)可以看出,ViewGroup會(huì)對(duì)它的每個(gè)孩子調(diào)用drawChild(), 在下面的例子中, ContentLinearLayout的孩子有2個(gè),是2個(gè)MyLinearLayout類(lèi)型的實(shí)例。

再看看drawChild函數(shù):protected boolean drawChild(Canvas canvas, View child, long drawingTime) {

................

................

child.computeScroll();

................

................

}

看到這里,我想大家應(yīng)該就明白了,在父容器重畫(huà)自己的孩子時(shí),它會(huì)調(diào)用孩子的computScroll方法,也就是說(shuō)例程中的ContentLinearLayout在調(diào)用dispatchDraw()函數(shù)時(shí)會(huì)調(diào)用MyLinearLayout的computeScroll方法。

這個(gè)computeScroll()函數(shù)正是我們大展身手的地方,在這個(gè)函數(shù)里我們可以去取得事先設(shè)置好的成員變量mScroller中的位置信息、速度信息等等,用這些參數(shù)來(lái)做我們想做的事情。

看到這里大家一定迫不及待的想看代碼了,代碼如下:package com.yulongfei.scroller;

import android.widget.LinearLayout;

import android.widget.Scroller;

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.widget.Button;

import android.view.View.OnClickListener;

public class TestScrollerActivity 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("MyButton", 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 [email?protected] android.widget.Scroller Scroller}

* object.

*/

public void computeScroll()

{

Log.d(TAG, this.toString() + " computeScroll-----------");

if (mScroller.computeScrollOffset())//如果mScroller沒(méi)有調(diào)用startScroll,這里將會(huì)返回false。

{

//因?yàn)檎{(diào)用computeScroll函數(shù)的是MyLinearLayout實(shí)例,

//所以調(diào)用scrollTo移動(dòng)的將是該實(shí)例的孩子,也就是MyButton實(shí)例

scrollTo(mScroller.getCurrX(), 0);

Log.d(TAG, "getCurrX = " + mScroller.getCurrX());

//繼續(xù)讓系統(tǒng)重繪

getChildAt(0).invalidate();

}

}

}

class ContentLinearLayout extends LinearLayout

{

public ContentLinearLayout(Context ctx)

{

super(ctx);

}

@Override

protected void dispatchDraw(Canvas canvas)

{

Log.d("ContentLinearLayout", "contentview dispatchDraw");

super.dispatchDraw(canvas);

}

}

}

對(duì)代碼做一個(gè)簡(jiǎn)單介紹:

例子中定義了2個(gè)MyButton實(shí)例btn1和btn2,它們將被其父容器MyLinearLayout實(shí)例lay1和lay2通過(guò)調(diào)用scrollTo來(lái)移動(dòng)。

ContentLinearLayout實(shí)例lay0為Activity的contentview,它有2個(gè)孩子,分別是lay1和lay2。

mScroller是一個(gè)封裝位置和速度等信息的變量,startScroll()函數(shù)只是對(duì)它的一些成員變量做一些設(shè)置,這個(gè)設(shè)置的唯一效果就是導(dǎo)致mScroller.computeScrollOffset() 返回true。

這里大家可能有個(gè)疑問(wèn),既然startScroll()只是虛晃一槍,那scroll的動(dòng)態(tài)效果到底是誰(shuí)觸發(fā)的呢?

后面我將給出答案。

運(yùn)行程序,我們來(lái)看看Log

點(diǎn)擊btn1:

點(diǎn)擊btn2:

對(duì)照Log,我從button被點(diǎn)擊開(kāi)始,對(duì)整個(gè)繪制流程進(jìn)行分析,首先button被點(diǎn)擊(這里將回答上文的問(wèn)題),button的背景將發(fā)生變化,這時(shí)button將調(diào)用invalidate()請(qǐng)求重繪,這就是View系統(tǒng)重繪的源頭,即scroll動(dòng)態(tài)效果的觸發(fā)者。與此同時(shí),mScroller.startScroll被調(diào)用了,mScroller在此時(shí)被設(shè)置了一些有效值。

好了,既然重繪請(qǐng)求已發(fā)出了,那么整個(gè)View系統(tǒng)就會(huì)來(lái)一次自上而下的繪制了,首先輸出的Log就是“contentview dispatchDraw”了,它將繪制需要重繪的孩子(lay1和lay2中的一個(gè)),接著會(huì)調(diào)用drawChild,使得computeScroll函數(shù)被觸發(fā)(drawChild里面會(huì)調(diào)用child.computeScroll()),于是,lay1或者lay2就會(huì)以mScroller的位置信息為依據(jù)來(lái)調(diào)用scrollTo了,它的孩子btn1或者btn2就會(huì)被移動(dòng)了。之后又調(diào)用了getChildAt(0).invalidate(),這將導(dǎo)致系統(tǒng)不斷重繪,直到startScroll中設(shè)置的時(shí)間耗盡mScroller.computeScrollOffset()返回false才停下來(lái)。

好了,現(xiàn)在整個(gè)流程都分析完了,相信大家應(yīng)該清楚了Scroller類(lèi)與View系統(tǒng)的關(guān)系了吧。理解了Scroller的工作原理,你會(huì)發(fā)現(xiàn)原來(lái)Scroller類(lèi)并不神秘,甚至有點(diǎn)被動(dòng),它除了儲(chǔ)存一些數(shù)值,什么其他的事情都沒(méi)做,Scroller類(lèi)中的一些變量mStartX, mFinalX, mDuration等等的意義也很好理解。

總結(jié):

一、mScroller.startScroll 并不會(huì)導(dǎo)致 View 立即進(jìn)行scroll,它只會(huì)導(dǎo)致當(dāng)前 View 無(wú)效,從而重新繪制,在 View 被它的parent View 調(diào)用繪制的時(shí)候,它的 computeScroll 函數(shù)會(huì)被調(diào)用,所以會(huì)在computeScroll這個(gè)函數(shù)中讓 View 調(diào)用 scrollTo 函數(shù)進(jìn)行實(shí)際的移動(dòng)。

mScroller 的純粹是一個(gè)Model,根據(jù)Animation提供數(shù)據(jù)而已,如果希望改變滾動(dòng)效果,例如快慢,回彈等,控制mScroller ,再讀取它的數(shù)據(jù)處理界面.

二、scoller只是封裝了將要滾動(dòng)的操作,并不是立即執(zhí)行的,執(zhí)行了startScroll方法后,調(diào)用了父控件的computeScroll方法來(lái)執(zhí)行的滾動(dòng)操作,并且滾動(dòng)并不是按鈕的滾動(dòng),而是布局滾動(dòng),那么里面的所有子元素也會(huì)跟著滾動(dòng)

總結(jié)

以上是生活随笔為你收集整理的android 最新消息滚动,Android 滚动操作Scroller类详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。