轉載自【移動開發】Android中三種超實用的滑屏方式匯總(ViewPager、ViewFlipper、ViewFlow)-狂奔的蝸牛-51CTO博客
現如今主流的Android應用中,都少不了左右滑動滾屏這項功能,(貌似現在好多人使用智能機都習慣性的有事沒事的左右滑屏,也不知道在干什么。。。嘿嘿),由于前段時間項目的需要,所以也對其研究了一下,總的來說滑屏實現有三種方式:(至于其他的實現方式目前后還沒碰到。。。)
1.ViewPager?2.ViewFlipper 3.ViewFlow
一.ViewPager
官方文檔介紹:http://developer.android.com/reference/android/support/v4/view/ViewPager.html
根據繼承關系我們可以看出,ViewPager不在android sdk 自帶jar包中,來源google 的補充組件android-support-v4.jar中,所以我們在3.0以前的版本中使用就需要導入該jar包了。
1.1 介紹:該類是一個布局管理器,它允許用戶通過滑動左、右頁的數據。你必須要一個實現了PagerAdapter接口從而生成的頁面視圖。
1.2 使用:
activity_main.xml
????xmlns:tools="http://schemas.android.com/tools"
????android:layout_width="match_parent"
????android:layout_height="match_parent"?>
????????android:id="@+id/viewpager"
????????android:layout_width="fill_parent"
????????android:layout_height="fill_parent"?/>
MainActivity類:
package?comzhf.android_viewpager;
import?java.util.ArrayList;
import?java.util.List;
import?android.os.Bundle;
import?android.app.Activity;
import?android.support.v4.view.ViewPager;
import?android.view.LayoutInflater;
import?android.view.View;
import?android.view.View.OnClickListener;
import?android.widget.Button;
import?android.widget.TextView;
import?android.widget.Toast;
/**
?* 主界面:ViewPagerViewPager不在android sdk 自帶jar包中,來源google 的補充組件android-support-v4.jar
?*/
public?class?ViewPagerActivity?extends?Activity {
????private?ViewPager mViewPager;
????List viewList;
????@Override
????protected?void?onCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.activity_main);
????????LayoutInflater mInflater = getLayoutInflater().from(this);
????????View v1 = mInflater.inflate(R.layout.layout1,?null);
????????View v2 = mInflater.inflate(R.layout.layout2,?null);
????????View v3 = mInflater.inflate(R.layout.layout3,?null);
????????//添加頁面數據
????????viewList =?new?ArrayList();
????????viewList.add(v1);
????????viewList.add(v2);
????????viewList.add(v3);
????????//實例化適配器
????????mViewPager = (ViewPager) findViewById(R.id.viewpager);
????????mViewPager.setAdapter(new?MyPagerAdapter(viewList));
????????mViewPager.setCurrentItem(0);?//設置默認當前頁
????????View view = viewList.get(0);
????????TextView textView = (TextView) view.findViewById(R.id.text_1);
????????textView.setText("我是第一頁");
????????Button button = (Button) view.findViewById(R.id.button_1);
????????button.setOnClickListener(new?OnClickListener() {
????????????public?void?onClick(View v) {
????????????????// TODO Auto-generated method stub
????????????????Toast.makeText(getApplicationContext(),?"你點擊了按鈕", Toast.LENGTH_SHORT).show();
????????????????}
????????});
????}
}
這里還有三個布局文件:layout1.xml (其余兩個類似,略)
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"
????android:orientation="vertical"
????android:background="@drawable/guide01"?>
????????android:id="@+id/text_1"
????????android:layout_width="wrap_content"
????????android:layout_height="wrap_content"
????????android:layout_gravity="center_horizontal"
????????android:text="葉片一"
????????android:textSize="25sp"?/>
????????android:id="@+id/button_1"
????????android:layout_width="fill_parent"
????????android:layout_height="wrap_content"
????????android:text="點擊我"
????????>
效果圖:
補充說明:
1.這里我們用了Layout作為每個page的填充數據,其實官方文檔說ViewPager+Fragment配合使用更好
2.每個頁面的響應事件我們可以在OnPageChangeListener監聽器類中進行捕獲和處理對應事件。
二.ViewFlipper
官方文檔:http://developer.android.com/reference/android/widget/ViewFlipper.html
2.1 介紹:ViewFilpper控件是系統自帶控件之一,主要用于在同一個屏幕間的切換及設置動畫效果、間隔時間,且可以自動播放。
順便提及一下,View動畫關系圖:
2.2 使用:
2.2.1 靜態加載:
activity_main.xml:
? ? xmlns:tools="http://schemas.android.com/tools"
????android:layout_width="match_parent"
????android:layout_height="match_parent"?>
????????android:id="@+id/body_flipper"
????????android:layout_width="fill_parent"
????????android:layout_height="fill_parent"
????????android:background="#f0f0f0"?>
????????????android:id="@+id/layout01"
????????????layout="@layout/page1"?/>
????????????android:id="@+id/layout02"
????????????layout="@layout/page2"?/>
????????????android:id="@+id/layout02"
????????????layout="@layout/page3"?/>
????????????android:id="@+id/layout02"
????????????layout="@layout/page4"?/>
MainActivity類:
package?com.zhf.android_viewflipper_view;
import?android.os.Bundle;
import?android.app.Activity;
import?android.view.MotionEvent;
import?android.view.View;
import?android.view.View.OnTouchListener;
import?android.view.animation.AnimationUtils;
import?android.widget.ViewFlipper;
/**
?* ViewFlipper 靜態加載
?* @author ZHF
**/
public?class?MainActivity?extends?Activity?implements?OnTouchListener{
????private?ViewFlipper viewFlipper;
????private?float touchDownX;?// 手指按下的X坐標
????private?float touchUpX;?//手指松開的X坐標
????@Override
????public?void?onCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.activity_main);
????????viewFlipper = (ViewFlipper) findViewById(R.id.body_flipper);
????????viewFlipper.setOnTouchListener(this);
????}
????@Override
????public?boolean onTouch(View v, MotionEvent event) {
????????if?(event.getAction() == MotionEvent.ACTION_DOWN) {
????????????// 取得左右滑動時手指按下的X坐標
????????????touchDownX = event.getX();
????????????return?true;
????????}?else?if?(event.getAction() == MotionEvent.ACTION_UP) {
????????????// 取得左右滑動時手指松開的X坐標
????????????touchUpX = event.getX();
????????????// 從左往右,看前一個View
????????????if?(touchUpX - touchDownX >?100) {
????????????????// 顯示上一屏動畫
????????????????viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
???????????????????????R.anim.push_right_in));
????????????????viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
????????????????????????R.anim.push_right_out));
????????????????// 顯示上一屏的View
????????????????viewFlipper.showPrevious();
????????????????// 從右往左,看后一個View
????????????}?else?if?(touchDownX - touchUpX >?100) {
????????????????//顯示下一屏的動畫
????????????????viewFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
????????????????????????R.anim.push_left_in));
????????????????viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
????????????????????????R.anim.push_left_out));
????????????????// 顯示下一屏的View
????????????????viewFlipper.showNext();
????????????}
????????????return?true;
????????}
????????return?false;
????}
}
動畫配置文件(右進右出同理,略):
push_left_in.xml:
????????android:duration="500"
????????android:fromXDelta="100.0%p"
????????android:toXDelta="0.0"?/>
????????android:duration="500"
????????android:fromAlpha="0.1"
????????android:toAlpha="1.0"?/>
push_left_out.xml:
????????android:duration="500"
????????android:fromXDelta="0.0"
????????android:toXDelta="-100.0%p"?/>
????????android:duration="500"
????????android:fromAlpha="1.0"
????????android:toAlpha="0.1"?/>
效果:
向左滑屏 向右滑屏
補充:
上述的page只有4個,而真實項目中的page頁面個數是不確定的,所以下面這種方式是項目中經常用到的。
2.2.2 動態加載(重要)
參考文章:http://blog.csdn.net/yuzhiboyi/article/details/7702953
activity_main2.xml
????xmlns:tools="http://schemas.android.com/tools"
????android:layout_width="match_parent"
????android:layout_height="match_parent"?>
????????android:id="@+id/body_flipper"
????????android:layout_width="fill_parent"
????????android:layout_height="fill_parent"
????????android:background="#f0f0f0"?>
flipper_view.xml:
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"
????android:scrollbars="none"?>
????????android:layout_width="fill_parent"
????????android:layout_height="wrap_content"
????????android:gravity="center"
????????android:orientation="vertical"?>
????????????android:layout_width="wrap_content"
????????????android:layout_height="wrap_content"
????????????android:src="@drawable/ic_launcher"?/>
????????????android:id="@+id/textView"
????????????android:textSize="100dip"
????????????android:layout_width="wrap_content"
????????????android:layout_height="wrap_content"?/>
注:這里并不是所有的View都能有onFling回調函數,外部需要加ScrollView !
MyGestureListener類:自定義滑動事件監聽器
package?com.zhf.android_viewflipper_view;
import?android.view.GestureDetector.SimpleOnGestureListener;
import?android.view.MotionEvent;
/**
?* 自定義滑動事件監聽器
?* SimpleOnGestureListener已經實現了OnGestureListener接口和OnDoubleTapListener接口,
?* 可以有選擇性的復寫需要的方法,提供方法onFling()作為滑動事件的回調函數
?* @author ZHF
?*
?*/
public?class?MyGestureListener?extends?SimpleOnGestureListener{
????private?OnFlingListener mOnFlingListener;
????/**用戶按下觸摸屏、快速移動后松開,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE, 1個ACTION_UP觸發 **/
????@Override
????public?final?boolean?onFling(final?MotionEvent e1,?final?MotionEvent e2,
????????????final?float?speedX,?final?float?speedY) {
????????if?(mOnFlingListener ==?null) {
????????????return?super.onFling(e1, e2, speedX, speedY);
????????}
????????float?XFrom = e1.getX();?//按下坐標
????????float?XTo = e2.getX();
????????float?YFrom = e1.getY();
????????float?YTo = e2.getY();
????????// 左右滑動的X軸幅度大于100,并且X軸方向的速度大于100
????????if?(Math.abs(XFrom - XTo) >?100.0f && Math.abs(speedX) >?100.0f) {
????????????// X軸幅度大于Y軸的幅度
????????????if?(Math.abs(XFrom - XTo) >= Math.abs(YFrom - YTo)) {
????????????????if?(XFrom > XTo) {
????????????????????// 下一個
????????????????????mOnFlingListener.flingToNext();
????????????????}?else?{
????????????????????// 上一個
????????????????????mOnFlingListener.flingToPrevious();
????????????????}
????????????}
????????}?else?{
????????????return?false;
????????}
????????return?true;
????}
????/**自定義滑動的回調接口**/
????public?interface?OnFlingListener {
????????void?flingToNext();?//滑動到下一頁
????????void?flingToPrevious();?//滑動到上一頁
????}
????public?OnFlingListener getOnFlingListener() {
????????return?mOnFlingListener;
????}
????public?void?setOnFlingListener(OnFlingListener mOnFlingListener) {
????????this.mOnFlingListener = mOnFlingListener;
????}
}
MyViewFlipper類:自定義View滑動類:監聽滑動事件,并做切換視圖的處理。
package?com.zhf.android_viewflipper_view;
import?android.content.Context;
import?android.util.AttributeSet;
import?android.view.GestureDetector;
import?android.view.MotionEvent;
import?android.view.View;
import?android.widget.ViewFlipper;
import?com.zhf.android_viewflipper_view.MyGestureListener.OnFlingListener;
/**
?* 自定義View滑動類:監聽滑動事件,并做切換視圖的處理。
?* @author ZHF
?*
?*/
public?class?MyViewFlipper?extends?ViewFlipper?implements?OnFlingListener {
????//手勢監聽類
????private?GestureDetector mGestureDetector =?null;
????private?OnViewFlipperListener mOnViewFlipperListener =?null;
????public?MyViewFlipper(Context context) {
????????super(context);
????}
????public?MyViewFlipper(Context context, AttributeSet attrs) {
????????super(context, attrs);
????}
????public?void?setOnViewFlipperListener(OnViewFlipperListener mOnViewFlipperListener) {
????????this.mOnViewFlipperListener = mOnViewFlipperListener;
????????//初始化自定義滑動事件監聽器
????????MyGestureListener myGestureListener =?new?MyGestureListener();
????????//綁定自定義的滑動監聽器
????????myGestureListener.setOnFlingListener(this);
????????mGestureDetector =?new?GestureDetector(myGestureListener);
????}
????@Override
????public?boolean onInterceptTouchEvent(MotionEvent ev) {
????????if?(null?!= mGestureDetector) {
????????????return?mGestureDetector.onTouchEvent(ev);
????????}?else?{
????????????return?super.onInterceptTouchEvent(ev);
????????}
????}
????/**向下一條滑動事件**/
????@Override
????public?void?flingToNext() {
????????if?(null?!= mOnViewFlipperListener) {
????????????int?childCnt = getChildCount();
????????????if?(childCnt ==?2) {
????????????????removeViewAt(1);
????????????}
????????????addView(mOnViewFlipperListener.getNextView(),?0);
????????????if?(0?!= childCnt) {
????????????????setInAnimation(getContext(), R.anim.push_left_in);
????????????????setOutAnimation(getContext(), R.anim.push_left_out);
????????????????setDisplayedChild(0);
????????????}
????????}
????}
????/**向上一條滑動事件**/
????@Override
????public?void?flingToPrevious() {
????????if?(null?!= mOnViewFlipperListener) {
????????????int?childCnt = getChildCount();
????????????if?(childCnt ==?2) {
????????????????removeViewAt(1);
????????????}
????????????addView(mOnViewFlipperListener.getPreviousView(),?0);
????????????if?(0?!= childCnt) {
????????????????setInAnimation(getContext(), R.anim.push_right_in);
????????????????setOutAnimation(getContext(), R.anim.push_right_out);
????????????????setDisplayedChild(0);
????????????}
????????}
????}
????/**自定義View變化監聽回調接口**/
????public?interface?OnViewFlipperListener {
????????View getNextView();?//獲取下一頁View
????????View getPreviousView();?//獲取上一頁View
????}
}
MainActivity2類:
package?com.zhf.android_viewflipper_view;
import?com.zhf.android_viewflipper_view.MyViewFlipper.OnViewFlipperListener;
import?android.app.Activity;
import?android.os.Bundle;
import?android.view.LayoutInflater;
import?android.view.View;
import?android.widget.ScrollView;
import?android.widget.TextView;
/**
?* ViewFlipper 動態加載
?* @author ZHF
?*/
public?class?MainActivity2?extends?Activity?implements?OnViewFlipperListener{
??????private?MyViewFlipper myViewFlipper;
??????private?int?currentNumber;
????@Override
????protected?void?onCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.activity_main2);
????????currentNumber =?1;?//默認頁號
????????myViewFlipper = (MyViewFlipper) findViewById(R.id.body_flipper);
????????//給ViewFlipper綁定自定義的滑動監聽器
????????myViewFlipper.setOnViewFlipperListener(this);
????????//初始化頁面數據,即View
????????myViewFlipper.addView(createView(currentNumber));
????}
????/**獲取下一頁View**/
????@Override
????public?View getNextView() {
????????currentNumber = currentNumber ==?10???1?: currentNumber +?1;
????????return?createView(currentNumber);
????}
????/**獲取上一頁View**/
????@Override
????public?View getPreviousView() {
????????currentNumber = currentNumber ==?1???10?: currentNumber -?1;
????????return?createView(currentNumber);
????}
????/**更換View數據:這里是根據頁號來更換textView上的文字**/
????private?View createView(int?currentNumber) {
????????LayoutInflater layoutInflater = LayoutInflater.from(this);
????????ScrollView resultView = (ScrollView) layoutInflater.inflate(R.layout.flipper_view,?null);
????????((TextView) resultView.findViewById(R.id.textView)).setText(currentNumber +?"");
????????return?resultView;
????}
}
效果圖:
--向左滑動(漸變過程不好截圖)-->?
補充說明:
上述的三個類:
MyGestureListener:繼承了SimpleGestureListener手勢監聽類, 復寫了該類onFling()方法,用于監聽用戶按下滑動事件的處理;還自定義了滑動的回調接口OnFlingListener(包含了兩個抽象方法flingToNext(),flingToPrevious)。
MyViewFlipper:是一個自定義ViewFlipper,該類首先實現和綁定了上一個類中的滑動的回調接口OnFlingListener,完成了接口中兩個重要的方法。同時定義了一個View變化監聽回調接口OnViewFlipperListener(包含了兩個抽象方法getNextView(),getPreviousView())。
MainActivity2:加載布局,實現監聽,統一處理頁面數據View和滑動事件的綁定。
三.ViewFlow類
3.1介紹:
ViewFlow不是google官方的api,它是gethub上的一個開源項目,利用ViewFlow可以產生視圖切換的效果。ViewFlow 相當于 Android UI 部件提供水平滾動的 ViewGroup,使用 Adapter 進行條目綁定,例如ViewPager或是ViewFlipper。它提供了三個組件ViewFlow、FlowIndicator和TitleFlowIndicator,一般情況下,當你需要做一個滑動然而不確定view的數目時,可以考慮使用ViewFlow。如果你的view數目確定,使用Fragments 或兼容庫里的ViewPager比較好 。
3.2使用:
A.首先下載ViewFlow開源庫代碼:
官方文檔:https://github.com/pakerfeldt/android-viewflow
B.下載之后我們解壓打開viewflow文件夾:
C.建項目將這三個類直接復制過來放項目中使用即可。
注:這里可能還需要一個styleable文件,直接將value文件夾下的attrs.xml拷入即可。
activity_main.xml
????xmlns:app="http://schemas.android.com/apk/res/com.zhf.android_viewflow"
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"
????android:orientation="vertical"?>
????????android:layout_width="fill_parent"
????????android:layout_height="fill_parent"
????????android:orientation="vertical"?>
????????????android:layout_width="fill_parent"
????????????android:layout_height="135dp"
????????????android:orientation="vertical"?>
????????????????android:id="@+id/viewflow"
????????????????android:layout_width="fill_parent"
????????????????android:layout_height="fill_parent"
????????????????app:sidebuffer="3"/>
????????????android:id="@+id/viewflowindic"
????????????android:layout_width="wrap_content"
????????????android:layout_height="140dp"
????????????android:layout_alignParentBottom="true"
????????????android:layout_gravity="center_horizontal"
????????????app:fadeOut="0"
????????????app:inactiveType="fill"
????????????android:paddingTop="125dp"?/>
????????????inactiveType(填充或描邊)、
????????????fadeOut(設置圓點自動隱藏的秒數,若為0則不會自動隱藏)、
????????????radius(圓點的半徑)等。
????????-->
注:這里需要強調一下,因為使用第三方的庫組件,所以要在使用之前引入:
xmlns:app="http://schemas.android.com/apk/res/com.zhf.android_viewflow"
main_item.xml
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"
????android:isScrollContainer="true"
????android:scrollbarAlwaysDrawVerticalTrack="true"
????android:scrollbars="vertical"?>
????scrollbarAlwaysDrawVerticalTrack????? 設置是否始終顯示垂直滾動條-->
????????android:id="@+id/imgView"
????????android:layout_width="fill_parent"
????????android:layout_height="wrap_content"
????????android:layout_gravity="center_vertical|center_horizontal"?>
MainActivity類
package?com.zhf.android_viewflow;
import?android.os.Bundle;
import?android.app.Activity;
import?android.content.res.Configuration;
public?class?MainActivity?extends?Activity {
????private?ViewFlow viewFlow;
????private?CircleFlowIndicator indic;?//頁表指示器
????@Override
????protected?void?onCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
????????setContentView(R.layout.activity_main);
????????viewFlow = (ViewFlow) findViewById(R.id.viewflow);
????????//為其綁定適配器
????????viewFlow.setAdapter(new?ImageAdapter(this),5);?//初始位置5
????????indic = (CircleFlowIndicator) findViewById(R.id.viewflowindic);
????????//為viewFlow綁定頁表指示器
????????viewFlow.setFlowIndicator(indic);
????}
????/**處理轉屏操作**/
????@Override
????public?void?onConfigurationChanged(Configuration newConfig) {
????????super.onConfigurationChanged(newConfig);
????????viewFlow.onConfigurationChanged(newConfig);
????}
}
這里還有一個圖片適配器:ImageAdapter
package?com.zhf.android_viewflow;
import?com.cjf.ui.R;
import?android.content.Context;
import?android.view.LayoutInflater;
import?android.view.View;
import?android.view.ViewGroup;
import?android.widget.BaseAdapter;
import?android.widget.ImageView;
public?class?ImageAdapter?extends?BaseAdapter{
????private?LayoutInflater mInflater;
????//圖片資源的id
????private?static?final?int[] ids = { R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d,
????????R.drawable.e, R.drawable.f, R.drawable.g, R.drawable.h};
????public?ImageAdapter(Context context) {
????????this.mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
????}
????@Override
????public?int?getCount() {
????????// TODO Auto-generated method stub
????????return?ids ==?null???0?:ids.length;
????}
????@Override
????public?Object?getItem(int?position) {
????????// TODO Auto-generated method stub
????????return?position;
????}
????@Override
????public?long getItemId(int?position) {
????????// TODO Auto-generated method stub
????????return?position;
????}
????@Override
????public?View getView(int?position, View convertView, ViewGroup parent) {
????????if?(convertView ==?null) {
????????????convertView = mInflater.inflate(R.layout.image_item,?null);
????????}
????????((ImageView) convertView.findViewById(R.id.imgView)).setImageResource(ids[position]);
????????return?convertView;
????}
}
運行一下吧!效果圖:
轉屏后?