代碼解說Android Scroller、VelocityTracker

在編寫自己定義滑動控件時經常會用到Android觸摸機制和Scroller及VelocityTracker。Android Touch系統簡單介紹(二):實例具體解釋onInterceptTouchEvent與onTouchEvent的調用過程對Android觸摸機制須要用到的函數進行了具體的解釋。本文主要介紹兩個重要的類:Scroller及VelocityTracker。利用上述知識,最后給出了一個自己定義滑動控件的demo,該demo類似于ImageGallery。

ImageGallery通常是用GridView來實現的,能夠左右滑動。本樣例實現的控件直接繼承一個ViewGroup,對其回調函數如 onTouchEvent、onInterceptTouchEvent、computeScroll等進行重載。弄懂該代碼。對Android touch的認識將會更深一層。

VelocityTracker:用于對觸摸點的速度跟蹤,方便獲取觸摸點的速度。
使用方法:一般在onTouchEvent事件中被調用。先在down事件中獲取一個VecolityTracker對象,然后在move或up事件中獲取速度,調用流程可例如以下列所看到的:

VelocityTracker vTracker = null;
@Override  
public boolean onTouchEvent(MotionEvent event){  int action = event.getAction();  switch(action){  case MotionEvent.ACTION_DOWN:  if(vTracker == null){  vTracker = VelocityTracker.obtain();  }else{  vTracker.clear();  }  vTracker.addMovement(event);  break;  case MotionEvent.ACTION_MOVE:  vTracker.addMovement(event);  //設置單位,1000 表示每秒多少像素(pix/second),1代表每微秒多少像素(pix/millisecond)。 vTracker.computeCurrentVelocity(1000);  //從左向右劃返回正數,從右向左劃返回負數System.out.println("the x velocity is "+vTracker.getXVelocity());  //從上往下劃返回正數,從下往上劃返回負數System.out.println("the y velocity is "+vTracker.getYVelocity());  break;  case MotionEvent.ACTION_UP:  case MotionEvent.ACTION_CANCEL:  vTracker.recycle();  break;  }  return true;  
}  


Scroller:用于跟蹤控件滑動的軌跡。此類不會移動控件,須要你在View的一個回調函數computerScroll()中使用Scroller對象還獲取滑動的數據來控制某個View。

  /*** 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()
{
}
parentView在繪制式。會調用dispatchDraw(Canvas canvas),該函數會調用ViewGroup中的每一個子view的boolean draw(Canvas canvas, ViewGroup parent, long drawingTime),用戶繪制View,此函數在繪制View的過程中會調用computeScroll()
以下給出一段代碼:
@Override
public void computeScroll() {	// TODO Auto-generated method stubLog.e(TAG, "computeScroll");if (mScroller.computeScrollOffset()) { //or !mScroller.isFinished()Log.e(TAG, mScroller.getCurrX() + "======" + mScroller.getCurrY());scrollTo(mScroller.getCurrX(), mScroller.getCurrY());Log.e(TAG, "### getleft is " + getLeft() + " ### getRight is " + getRight());postInvalidate();}elseLog.i(TAG, "have done the scoller -----");
}
這段代碼在滑動view之前先調用mScroller.computeScrollOffset()來推斷滑動動畫是否已結束。computerScrollerOffset()的源碼例如以下:

/*** Call this when you want to know the new location.  If it returns true,* the animation is not yet finished.*/ 
public boolean computeScrollOffset() {if (mFinished) {return false;}//滑動已經持續的時間int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);//若在規定時間還未用完,則繼續設置新的滑動位置mCurrX和mCurryif (timePassed < mDuration) {switch (mMode) {case SCROLL_MODE:float x = timePassed * mDurationReciprocal;if (mInterpolator == null)x = viscousFluid(x); elsex = mInterpolator.getInterpolation(x);mCurrX = mStartX + Math.round(x * mDeltaX);mCurrY = mStartY + Math.round(x * mDeltaY);break;case FLING_MODE:final float t = (float) timePassed / mDuration;final int index = (int) (NB_SAMPLES * t);float distanceCoef = 1.f;float velocityCoef = 0.f;if (index < NB_SAMPLES) {final float t_inf = (float) index / NB_SAMPLES;final float t_sup = (float) (index + 1) / NB_SAMPLES;final float d_inf = SPLINE_POSITION[index];final float d_sup = SPLINE_POSITION[index + 1];velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);distanceCoef = d_inf + (t - t_inf) * velocityCoef;}mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));// Pin to mMinX <= mCurrX <= mMaxXmCurrX = Math.min(mCurrX, mMaxX);mCurrX = Math.max(mCurrX, mMinX);mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));// Pin to mMinY <= mCurrY <= mMaxYmCurrY = Math.min(mCurrY, mMaxY);mCurrY = Math.max(mCurrY, mMinY);if (mCurrX == mFinalX && mCurrY == mFinalY) {mFinished = true;}break;}}else {mCurrX = mFinalX;mCurrY = mFinalY;mFinished = true;}return true;
}
ViewGroup.computeScroll()被調用時機:
當我們運行ontouch或invalidate()或postInvalidate()都會導致這種方法的運行。

我們在開發控件時。常會有這種需求:當單機某個button時。某個圖片會在規定的時間內滑出窗體。而不是一下子進入窗體。實現這個功能能夠使用Scroller來實現。
以下給出一段代碼,該代碼控制下一個界面在3秒時間內緩慢進入的效果。

public void moveToRightSide(){if (curScreen <= 0) {return;}curScreen-- ;Log.i(TAG, "----moveToRightSide---- curScreen " + curScreen);mScroller.startScroll((curScreen + 1) * getWidth(), 0, -getWidth(), 0, 3000);scrollTo(curScreen * getWidth(), 0);invalidate();
}
上述代碼用到了一個函數:void android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration)
當startScroll運行過程中即在duration時間內,computeScrollOffset ?方法會一直返回true,但當動畫運行完畢后會返回返加false.
這個函數的源代碼例如以下所看到的,主要用于設置滑動參數

/*** Start scrolling by providing a starting point, the distance to travel,* and the duration of the scroll.* * @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;
}
invalidate()會使得視圖重繪,導致parent調用了dispatchDraw(Canvas canvas),然后遞歸調用child View的draw()函數。該函數又會調用我們定義的computeScroll(), 而這個函數又會調用mScroller.computeScrollOffset()推斷動畫是否結束。若沒結束則繼續重繪直到直到startScroll中設置的時間耗盡mScroller.computeScrollOffset()返回false才停下來。

附上完整的實例代碼:

自己定義Android可滑動控件源代碼

執行效果圖例如以下,滑動屏幕會顯示不同的圖片。







轉載于:https://www.cnblogs.com/claireyuancy/p/6714587.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252899.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252899.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252899.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Effective_STL 學習筆記(四十四) 盡量使用成員函數代替同名的算法

有些容器擁有和 STL 算法同名的成員函數。 關聯容器提供了 count、find、lower_bound、upper_bound 和 euqal_range list 提供了 remove、remove_if、unique、merge 和 reverse 大多數時候應該用成員函數代替手寫算法&#xff0c;這樣做的兩個理由&#xff1a; 比起算法&#x…

(NFS移植到arm上)編譯portmap和nfs-utils

為了在播放機上實現NFS服務器的功能&#xff0c;我們已經在uClibc中打開了完整RPC支持&#xff0c;并且在新編譯的內核中打開了NFS服務器支持。此外還有兩個軟件包也是提供NFS服務所必需的&#xff1a;portmap和nfs-utils。portmap為RPC程序提供端口映射服務&#xff0c;nfs-ut…

HTML5上傳預覽

http://cobain-li.iteye.com/blog/2296538轉載于:https://www.cnblogs.com/winyh/p/7850049.html

支付寶支付

1 申請商戶平臺 2 申請開放平臺 3 申請APP支付 4 創建應用 (名稱&#xff0c;logo) 5 生成RSA秘鑰&#xff08;公鑰&#xff0c;私鑰&#xff09; 6 在應用中配置公鑰 7 配置其他內容&#xff0c;包括iOS bundle ID。配置安卓包名&#xff0c;和簽名。 獲取appid&#xff0c;公…

HttpRequest Java原生代碼封裝

HttpRequest Java原生代碼封裝 get提交 post提交 name1value1&name2value2 的形式 json形式兩種形式 package com.beisun.mbp.mbp.controller;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWrit…

Linux 系統目錄

/ 根目錄 /bin 存放必要的命令 /boot 存放內核以及啟動所需的文件等 /dev 存放設備文件 /etc 存放系統的配置文件 /home 用戶文件的主目錄&#xff0c;用戶數據存放在其主目錄中 /lib 存放必要的運行庫 /mnt 存放臨時的映射文件系統&#xff0c;我們常把軟驅和光驅掛裝在這里的…

linux多線程學習設置線程調度權限

pthread_setschedparam 設置線程的權限 int pthread_setschedparam(pthread_t target_thread, int policy, const struct sched_param *param) 參數 1. target_thread是使用pthread_create所獲得的線程ID。   2&#xff0e;線程的調度有三種策略&#xff1a;SCHED_OTHER、…

不可錯過的CMS學習筆記

引子 帶著問題去學習一個東西&#xff0c;才會有目標感&#xff0c;我先把一直以來自己對CMS的一些疑惑羅列了下&#xff0c;希望這篇學習筆記能解決掉這些疑惑&#xff0c;希望也能對你有所幫助。 CMS出現的初衷、背景和目的&#xff1f; CMS的適用場景&#xff1f; CMS的tr…

團隊合作及個人成長

通過前一章的學習&#xff0c;我了解到了關于建模的很多初步的知識&#xff0c;但是這和成為一名軟件工程師是遠遠不夠的&#xff0c;完成一個程序通常都是一個團隊&#xff0c;而這個團隊重要的肯定是需要一些流程&#xff0c;這樣才能讓程序有條不紊的運行著。在這么一個團隊…

相機工作原理

輕輕一按&#xff0c;你的相機就把光子轉換為了比特。于是一張相片就保存到了你的 iPhone 里。 讓我們假設一下你身處室外&#xff0c;環顧四周。三億里之外&#xff0c;太陽無時無刻不在發射光子。它們需要花上 8 分鐘之久才能到達我們舒適的星球。有一些光子撞擊到你周圍的物…

Android Studio使用心得

說實話 開始接觸這個工具 真的認為非常惡心 畢竟大陸被墻 非常多東西用起來不是非常方便 并且Eclipse轉到Android Studio還是一個跨度 廢話不多說 以下 講下我遇到的問題 1. 安裝的時候&#xff08;Setup Wizard - Download Components&#xff09; 這個要下載非常長時間 甚至…

CentOS用戶和用戶組的操作

2019獨角獸企業重金招聘Python工程師標準>>> CentOS用戶和用戶組的操作 長得太帥忚四種檌 關注 2018.05.12 16:40* 字數 312 閱讀 115評論 0喜歡 0 用戶組的操作 1.添加用戶組&#xff1a; groupadd 組名2.修改組名 groupmod -n 新組名 原組名刪除用戶組groupdel 組…

vue webpack配置分析

寫在前面&#xff1a;作為 Vue 的使用者我們對于 vue-cli 都很熟悉&#xff0c;但是對它的 webpack 配置我們可能關注甚少&#xff0c;今天我們為大家帶來 vue-cli#2.0 的 webpack 配置分析 vue-cli 的簡介、安裝我們不在這里贅述&#xff0c;對它還不熟悉的同學可以直接訪問 v…

Linux用戶空間與內核地址空間

Linux 操作系統和驅動程序運行在內核空間&#xff0c;應用程序運行在用戶空間&#xff0c;兩者不能簡單地使用指針傳遞數據&#xff0c;因為Linux使用的虛擬內存機制&#xff0c;用戶空間的數據可能被換出&#xff0c;當內核空間使用用戶空間指針時&#xff0c;對應的數據可能不…

關于主鍵的設計、primary key

主鍵&#xff1a;用于唯一標識一個表中一行數據。 外鍵&#xff1a;用于建立兩個表之間的關系&#xff0c;A表中有一列是B表中的主鍵&#xff0c;那么A表中這列的數據就受到B表主鍵的約束。 那么關于主鍵應該如何設計呢&#xff0c;這里我說下優缺點&#xff1a; 1.用自動增長字…

淺談微信smali注入

作者&#xff1a;郭少雷 搞android搞了幾年也沒搞出個啥牛逼app出來&#xff0c;眼看時下最火的app微信如此火熱&#xff0c;實在想搞搞它&#xff0c;索性就想著給它加點東西進去。 以下內容純屬本人個人愛好&#xff0c;僅限個人學習android用途以及對android的深入了解。 首…

從0到1使用Kubernetes系列(四):搭建第一個應用程序

上一篇文章《從0到1使用Kubernetes系列&#xff08;三&#xff09;&#xff1a;使用Ansible安裝Kubernetes集群》中&#xff0c;我們搭建了一套Kubernetes集群&#xff0c;接下來將在本文中介紹如何使用Kubernetes部署一個Nginx并通過Pod IP、Service IP、Ingress這三種方式訪問…

Embeded linux之移植iptables

一、內核環境&#xff1a; linux-3.4.35 -*- Networking support ---> Networking options ---> [*] Network packet filtering framework (Netfilter) ---> IP: Netfilter Configuration ---> <*> IP tables support (required for filtering/masq/NAT)…

Hadoop HIVE

數據倉庫工具。構建在hadoop上的數據倉庫框架&#xff0c;可以把hadoop下的原始結構化數據變成Hive中的表。&#xff08;主要解決ad-hoc query&#xff0c;即時查詢的問題&#xff09; 支持一種與SQL幾乎完全相同的語言HQL。除了不支持更新&#xff0c;索引和事務&#xff0c;幾…

Xcode9學習筆記67 - 打印查看程序沙箱結構中常用的幾個目錄

override func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view, typically from a nib.//首先獲得應用程序目錄的路徑&#xff0c;在該目錄下有三個文件夾&#xff1a;文檔目錄、庫目錄、臨時目錄以及一個程序包。該目錄就是應用程序的…