找了好久才發現的文章
轉自:http://archive.cnblogs.com/a/2265135/
第一種: ViewFlipper + GestureDetector;
第二種:自己重寫ViewGroup來管理view;
第三種:利用系統內建的ViewPager。
關於第一種方法,很多人用過就只說一下思路:用ViewSwitcher,加上動畫效果就可以做到。
第二種方法參考:http://marshal.easymorse.com/archives/3828,我在這裡就直接貼過來了:
上述,是手指拖動的效果,如果拖動過螢幕中點,鬆手後就會自動移動到第二屏。另外,如果使用撥動手勢,也可以自動移動下一屏。
主要是參考了這個項目:
http://code.google.com/p/andro-views/
有原始碼,不過他的代碼有兩個問題:
- 有bug,在特定情況下,可能兩屏會同時出現,類似上面第三張圖,不能切換過去,這可能是作者漏掉了一些touch狀態可能性造成的
- 代碼比較繁雜,作者估計是參考Android原始碼來寫的,有些代碼複製自Android代碼,比如ViewGroup,另外可能參考了ScrollView等
看到eric的實現,讓我明白以前的animation動畫處理以及通過修改空白邊(margin)的方式都不是正道。正道是使用Scroller,這是一個帶動畫支援的滾屏協助類。
使用Scroller的基本思路是,比如在本例中,將多個子視圖(ImageView)橫向排列到布局中(自己實現的布局),然後,通過Scroller可支援類似Windows下捲軸橫向移動的效果,而且是帶動畫的。比如,Scroller的方法:
- startScroll(int startX, int startY, int dx, int dy),設定x軸和y軸的起點及移動的距離,調用該方法將執行滾動動畫,動畫時間是250毫秒,也可以用重載的另外一個方法,可設定動畫周期
- abortAnimation(),停止動畫,那麼移動螢幕也會中止,目前我的版本中沒有用到,用的場合是撥動手勢後,又做了按下的手勢
- computeScrollOffset(),判斷是否移動到指定位置,用於移動過程中調用,如果未到位將繼續移動,產生動畫移動的效果,在本例中,覆蓋ViewGroup的computeScroll方法,在裡面調用了該方法
對Scroller的調用,要在布局(Layout)中進行。
Android中的View有兩個子類,Widget和ViewGroup,Widget是可見的視窗組件,比如按鈕,ViewGroup就是布局,ViewGroup已經提供了多個布局子類,比如LinearLayout等。
本例中實現了自己的ViewGroup子類。
通過覆蓋onLayout方法實現對子視圖的橫向排列布局:
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
Log.d(TAG, ">>left: " + left + " top: " + top + " right: " + right
+ " bottom:" + bottom);
/**
* 設定布局,將子視圖順序橫屏排列
*/
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.setVisibility(View.VISIBLE);
child.measure(right – left, bottom – top);
child.layout(0 + i * getWidth(), 0, getWidth() + i * getWidth(),
getHeight());
通過覆蓋computeScroll方法,計算移動螢幕的位移和重新繪製螢幕:
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), 0);
postInvalidate();
}
}
編寫了一個名為scrollToScreen的方法,用於根據指定螢幕號切換到該螢幕:
/**
* 切換到指定屏
*
* @param whichScreen
*/
public void scrollToScreen(int whichScreen) {
if (getFocusedChild() != null && whichScreen != currentScreenIndex
&& getFocusedChild() == getChildAt(currentScreenIndex)) {
getFocusedChild().clearFocus();
}
final int delta = whichScreen * getWidth() – getScrollX();
scroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);
invalidate();
currentScreenIndex = whichScreen;
}
snapToDestination方法,是處理當螢幕拖動到一個位置鬆手後的處理:
/**
* 根據當前x座標位置確定切換到第幾屏
*/
private void snapToDestination() {
scrollToScreen((getScrollX() + (getWidth() / 2)) / getWidth());
}
然後說說手勢事件的處理。eric的實現,全部使用onTouch事件處理,這樣代碼不夠簡明。因為需要記錄很多組合手勢的曆史資料,這樣就必須有一些狀態位,一些座標數值。
我用GestureDetector的手勢處理事件簡化了這方面的處理,只在手勢抬起(UP)事件處理中在ouTouchEvent方法中做了處理。
具體代碼見:http://easymorse.googlecode.com/svn/tags/ScrollDemos-0.6/
升級版本:
在此基礎上又實現了個版本,結合了Page Control效果。另外換了個表單視圖,來說明方案的通用性。
原始碼見:http://easymorse.googlecode.com/svn/tags/ScrollDemos-0.7/
第三種方法:詳見:http://blog.csdn.net/billpig/article/details/6650097
起初最早接觸到左右兩個螢幕切換的是在 《創新源於模仿之三:實現左右兩個螢幕的切換》 這篇文章上,感謝作者為我們提供了這麼好的DEMO。
什麼是ViewPager呢?
它是實現左右兩個螢幕平滑地切換的一個類,它是Google提供的,作為Android的一個補充。先上個把,讓大家有個直觀的認識。
我們在網上搜尋這相關到主題的時候,會看到有很多關於這方面的問題:如何平滑?水平移動?等等。現在,我們可以自己不去親自做這個費力的事情了,只需要使用到一個叫ViewPager的類即可。ViewPager是最近在Compatibility package發布的,支援android 1.6+,如果要使用的話,要通過SDK Manager去更新Compatibility
package,具體使用方法在<SDK_DOC_PATH>/sdk/compatibility-library.html(SDK_DOC_PATH是內建Android文檔的位置,需要更新到最新的文檔才有)。
《創新源於模仿之三:實現左右兩個螢幕的切換》提供了Workspace實現了左右螢幕的切換,現在Google I/O上已經發布了這樣的Workspace類,方便我們大家去使用,稍後我會同本文DEMO的原始碼一起發布。那ViewPager和Workspace有什麼樣的區別呢?先看下api doc的說法:
Layout manager that allows the user to flip left and right through pages of data. You supply an implementation of a PagerAdapter
to generate the pages that the view shows.
如上所述,ViewPager提供了一個適配器,方便我們對各個View進行控制,而Workspace需要我們手動去添加,它相當於是一個"靜態切換"。接下來我將介紹下如何使用:
1、下載來Android SDK & AVD manager的更新:Available Packages -> Android Repository -> Android Compatibility Package, revision 3. 它將安裝在\extras\android\compatibility\v4檔案下
2、建立一個Android項目,在上述安裝目錄下把 android-support-v4.jar添加進項目,如果是最新的ADT,只需要右擊project->Android Tools->Add Compatibility Library
3、在Activity中使用ViewPager
4、如果ViewPager是用xml去定義的,需要寫上全域的路徑,如:
- <android.support.v4.view.ViewPager
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/awesomepager"/>
5、建立一個PagerAdapter,實現如下方法:
getCount(), instantiateItem(), destroyItem(), isViewFromObject() 。
總上所述,貼上俺的代碼,我們發現,可以很快很簡單的實現左右兩個螢幕的切換
- public class AwesomePagerActivity extends Activity {
-
- private ViewPager awesomePager;
-
- private Context cxt;
- private AwesomePagerAdapter awesomeAdapter;
-
- private LayoutInflater mInflater;
- private List<View> mListViews;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- cxt = this;
-
- awesomeAdapter = new AwesomePagerAdapter();
- awesomePager = (ViewPager) findViewById(R.id.awesomepager);
- awesomePager.setAdapter(awesomeAdapter);
-
- mListViews = new ArrayList<View>();
- mInflater = getLayoutInflater();
- mListViews.add(mInflater.inflate(R.layout.layout1, null));
- mListViews.add(mInflater.inflate(R.layout.layout2, null));
- mListViews.add(mInflater.inflate(R.layout.layout3, null));
-
- }
-
- private class AwesomePagerAdapter extends PagerAdapter{
-
-
- @Override
- public int getCount() {
- return mListViews.size();
- }
-
- /**
- * 從指定的position建立page
- *
- * @param container ViewPager容器
- * @param position The page position to be instantiated.
- * @return 返回指定position的page,這裡不需要是一個view,也可以是其他的視圖容器.
- */
- @Override
- public Object instantiateItem(View collection, int position) {
-
-
- ((ViewPager) collection).addView(mListViews.get(position),0);
-
- return mListViews.get(position);
- }
-
- /**
- * <span >從指定的position銷毀page</span>
- *
- *
- *<span >參數同上</span>
- */
- @Override
- public void destroyItem(View collection, int position, Object view) {
- ((ViewPager) collection).removeView(mListViews.get(position));
- }
-
-
-
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return view==(object);
- }
-
- @Override
- public void finishUpdate(View arg0) {}
-
-
- @Override
- public void restoreState(Parcelable arg0, ClassLoader arg1) {}
-
- @Override
- public Parcelable saveState() {
- return null;
- }
-
- @Override
- public void startUpdate(View arg0) {}
-
- }
-
-
- }
就這樣,我們可以很容易就實現左右兩個螢幕之間的切換。具體頁面到內容就靠大家去發揮了!