Android中啟動頁ViewPager和ViewFlipper帶指示器
首先我們來分析一下,想要實現啟動頁的功能,大家第一個想到的就是使用ViewPager,使用ViewPager確實是一種比較好的方式,而且思路也是比較清晰的。今天我們就一起來學習一下,使用ViewPager和ViewFlipper實現啟動頁帶小點功能。
先展示一下圖片,看看是不是你想要的效果。
1、ViewPager和ViewFlipper的區別
ViewFlipper繼承ViewAnimator,切換view的時候是有動畫效果的,適合做ppt,多介面的程式歡迎引導介面,算是個輕量級的元件,適合展示靜態資料,少量資料。
ViewPager繼承ViewGroup。看官網描述,這貨和Fragment是好搭檔,Fragment有自己的生命週期。也就是說ViewPager更適用複雜的檢視切換,而且Viewpager有自己的adapter,這也讓其適應複雜物件,實現資料的動態載入。
2、使用ViewPager來展示mipmap中或者網路中的圖片(Volley)
首先,我們來理一下有幾個注意點。
①先在佈局檔案中,畫出簡單的佈局。
②滑動ViewPager時候,底部的小點也會跟著變化。
③點選小點時,ViewPager也會變化。
好了,現在我們來開始寫程式碼,程式碼中的註釋比較詳細,大家自己看。
1、佈局檔案中,畫出佈局。
layout中,activity_view_pager_demo.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.llay.admin.mydemo.ViewPagerDemoActivity">
<android.support.v4.view.ViewPager
android:id ="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
<LinearLayout
android:id="@+id/ll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:background="@drawable/point_selector"
android:clickable="true"
android:padding="5dp" />
<ImageView
android:id="@+id/iv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:background="@drawable/point_selector"
android:clickable="true"
android:padding="5dp" />
<ImageView
android:id="@+id/iv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:background="@drawable/point_selector"
android:clickable="true"
android:padding="5dp" />
<ImageView
android:id="@+id/iv4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:background="@drawable/point_selector"
android:clickable="true"
android:padding="5dp" />
</LinearLayout>
</RelativeLayout>
解釋:程式碼中使用相對佈局,這樣,下面的指示器就可以顯示在ViewPager上面,這樣便於效果的實現。我這裡下面的指示器是固定寫的,根據圖片的多少進行新增和刪除。
最後一個layout檔案單獨寫的:
activity_view_pager4.xm
public class ViewPagerDemoActivity extends Activity implements ViewPager.OnPageChangeListener, View.OnClickListener {
//設定ViewPager和view檢視
private ViewPager viewPager;
private int[] imageId = {R.mipmap.launcher_b, R.mipmap.launcher_c, R.mipmap.launcher_b};
private List<View> viewList;
private List<ImageUrlBean> imageList;
private View lastView;
//設定小圓點
private ImageView[] points;//存放小圓圈陣列
private int currentIndex = 0;//當前頁面,預設首頁
//使用Volley載入網路圖片
private RequestQueue mQueue;
private ImageLoader mImageLoader;
ImageLoader.ImageListener imageListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_view_pager_demo);
mQueue = Volley.newRequestQueue(this);
// initViewPage();
initNetView();
initPoints();
}
//這裡是載入mipmap中圖片的方式,初始化ViewPager及其圖片資源
private void initViewPage() {
viewPager = (ViewPager) findViewById(R.id.view_pager);
viewList = new ArrayList<>();
//新增對應的view進入集合(資料來源)
for (int i = 0; i < imageId.length; i++) {
ImageView imageView = new ImageView(this);
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);//設定縮放樣式
imageView.setImageResource(imageId[i]);
viewList.add(imageView);
}
//另外增加最後一個能點選進入應用的檢視
lastView = View.inflate(this, R.layout.activity_view_pager4, null);
Button button = (Button) lastView.findViewById(R.id.startbutton);
viewList.add(lastView);
//設定最後一個檢視上的點選事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(ViewPagerDemoActivity.this, "應用開始!", Toast.LENGTH_SHORT).show();
}
});
//設定viewpager的介面卡和資料來源
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(viewList);
viewPager.setAdapter(viewPagerAdapter);
viewPager.setOnPageChangeListener(this);
}
//這裡是載入網路圖片的方式,初始化ViewPager控制元件及其圖片資源
private void initNetView() {
viewPager = (ViewPager) findViewById(R.id.view_pager);
ImageUrlBean imageUrlBean1 = new ImageUrlBean("http://www.qq6300.com/uploads/allimg/130131/1-1301311G339A9.jpg");
ImageUrlBean imageUrlBean2 = new ImageUrlBean("http://img4.duitang.com/uploads/item/201412/13/20141213114411_QEshv.jpeg");
ImageUrlBean imageUrlBean3 = new ImageUrlBean("http://pic27.nipic.com/20130329/10041959_102531181000_2.jpg");
imageList = new ArrayList<>();
imageList.add(imageUrlBean1);
imageList.add(imageUrlBean2);
imageList.add(imageUrlBean3);
//新增對應的view進入集合(資料來源)
viewList = new ArrayList<>();
for (int i = 0; i < imageList.size(); i++) {
ImageView imageView = new ImageView(this);
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);//設定縮放樣式
mImageLoader = new ImageLoader(mQueue, new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String s) {
return null;
}
@Override
public void putBitmap(String s, Bitmap bitmap) {
}
});
imageListener = ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
mImageLoader.get(imageList.get(i).getImageUrl(), imageListener);
viewList.add(imageView);
}
//另外增加最後一個能點選進入應用的檢視
lastView = View.inflate(this, R.layout.activity_view_pager4, null);
Button button = (Button) lastView.findViewById(R.id.startbutton);
viewList.add(lastView);
//設定最後一個檢視上的點選事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(ViewPagerDemoActivity.this, "應用開始!", Toast.LENGTH_SHORT).show();
}
});
//設定viewpager的介面卡和資料來源
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(viewList);
viewPager.setAdapter(viewPagerAdapter);
viewPager.setOnPageChangeListener(this);
}
//初始化下標點
private void initPoints() {
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll);
points = new ImageView[4];
//初始化佈局中的小圓點ImageView控制元件
for (int i = 0; i < points.length; i++) {
points[i] = (ImageView) linearLayout.getChildAt(i);//遍歷LinearLayout下的所有ImageView子節點
points[i].setEnabled(true);//設定當前狀態為允許點選(可點,灰色)
points[i].setOnClickListener(this);//設定點選監聽
//額外設定一個識別符號,以便點選小圓點時跳轉對應頁面
points[i].setTag(i);//識別符號與圓點順序一致
}
currentIndex = 0;
points[currentIndex].setEnabled(false);//設定首頁為當前頁(不可點,黑色)
}
@Override
public void onClick(View v) {
viewPager.setCurrentItem((int) v.getTag());
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//當前頁卡被選擇時,position為當前頁數
points[position].setEnabled(false);//不可點選
points[currentIndex].setEnabled(true);//恢復之前頁面狀態
currentIndex = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
解釋:這裡有幾個地方需要注意的,
1、這裡新增資料來源的方式,有兩種方式:mipmap檔案中和網路上的圖片地址,我想,大家使用啟動頁功能的時候,一定是想要動態的從網路上獲取吧,這樣才能夠獲得最新的資料。
2、使用載入網路圖片功能,作者使用的是Volley框架,別問我為啥選這個啊,因為其他還沒用過,哈哈。
3、好了,這裡我們遇到了文章開頭時遇到的問題,當滑動ViewPager時,指示器也要跟著滑動,這裡我們繼承ViewPager.OnPageChangeListener,實現一些常用的方法,程式碼中都有註釋,請自行檢視。
4、還有一個是點選指示器的時候,ViewPager也跟著一起滑動。這裡我們繼承View.OnClickListener方法,這個方法就是點選事件,viewPager.setCurrentItem((int) v.getTag());便可以跳轉到所點選的介面,然後指示器在跳到指定介面之後,也會有相應的顏色變化。
3、ViewPager的介面卡程式碼
ViewPagerAdapter.javpublic class ViewPagerAdapter extends PagerAdapter {
private List list;
public ViewPagerAdapter(List list) {
this.list = list;
}
//獲取要滑動的控制元件的數量,在這裡我們以滑動的廣告欄為例,那麼這裡就應該是展示的廣告圖片的ImageView數量
@Override
public int getCount() {
return list.size();
}
//來判斷顯示的是否是同一張圖片,這裡我們將兩個引數相比較返回即可
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;//官方demo給出的建議寫法
}
//當要顯示的圖片可以進行快取的時候,會呼叫這個方法進行顯示圖片的初始化,我們將要顯示的ImageView加入到ViewGroup中,然後作為返回值返回即可
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(list.get(position));
return list.get(position);
}
//PagerAdapter只快取三張要顯示的圖片,如果滑動的圖片超出了快取的範圍,就會呼叫這個方法,將圖片銷燬
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(list.get(position));
}
}示器的佈局。
現在,我們來實現一下指示器的圓點,之前我一直以為,指示器的圓點就是讓UI畫出來的,原來還可以通過這種方式來實現。直接上程式碼。
未點選的圓點。
drawable檔案中。v_point_up.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<corners android:radius="0.5dp" />
<solid android:color="#AAFFFFFF" />
</shape>
點選的圓點。
drawable檔案中。v_point_down.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<corners android:radius="0.5dp" />
<solid android:color="#55000000" />
</shape>
主佈局檔案中的point_selector.xml檔案,這個檔案的功能是在選擇指示器之後,可以讓指示器的顏色用程式碼改變。
drawbale檔案中。point_selector.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/v_point_up" android:state_enabled="true"></item>
<item android:drawable="@drawable/v_point_down" android:state_enabled="false"></item>
</selector>
解釋:請注意這裡是android:state_enabled屬性,表示狀態是否可以點選。
2、使用ViewFlipper來展示mipmap中的圖片
這裡我沒有用ViewFlipper來展示網路圖片
1、佈局檔案:
同上ViewPager中的主佈局檔案和第四個佈局檔案,還有指示器的佈局檔案。
2、ViewFlipperActivity.java檔案
public class ViewFlipperActivity extends Activity implements GestureDetector.OnGestureListener, View.OnClickListener {
//設定ViewFlipper和view檢視
private ViewFlipper viewFlipper;
private int[] imageId = {R.mipmap.launcher_b, R.mipmap.launcher_c, R.mipmap.launcher_b};
View lastView;
//設定小圓點
private ImageView[] points;//存放小圓圈陣列
private int currentIndex = 0;//當前頁面,預設首頁
//設定手勢
GestureDetector gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_view_flipper);
gestureDetector = new GestureDetector(ViewFlipperActivity.this);
initViewFlipper();
initPoints();
}
//初始化ViewFlipper
private void initViewFlipper() {
viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper);
//新增對應的view進入集合(資料來源)
for (int i = 0; i < imageId.length; i++) {
ImageView imageView = new ImageView(this);
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);//設定縮放樣式
imageView.setImageResource(imageId[i]);
viewFlipper.addView(imageView);
}
//另外增加最後一個能點選進入應用的檢視
lastView = View.inflate(this, R.layout.activity_view_pager4, null);
Button button = (Button) lastView.findViewById(R.id.startbutton);
viewFlipper.addView(lastView);
//設定最後一個檢視上的點選事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(ViewFlipperActivity.this, "應用開始!", Toast.LENGTH_SHORT).show();
}
});
}
//初始化下標點
private void initPoints() {
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll);
points = new ImageView[4];
//初始化佈局中的小圓點ImageView控制元件
for (int i = 0; i < points.length; i++) {
points[i] = (ImageView) linearLayout.getChildAt(i);//遍歷LinearLayout下的所有ImageView子節點
points[i].setEnabled(true);//設定當前狀態為允許點選(可點,灰色)
points[i].setOnClickListener(this);//設定點選監聽
//額外設定一個識別符號,以便點選小圓點時跳轉對應頁面
points[i].setTag(i);//識別符號與圓點順序一致
}
currentIndex = 0;
points[currentIndex].setEnabled(false);//設定首頁為當前頁(不可點,黑色)
}
@Override
public void onClick(View v) {
//點選小點,改變小點的狀態,並且改變viewFlipper中子view的顯示
viewFlipper.setDisplayedChild((int) v.getTag());
points[(int) v.getTag()].setEnabled(false);
points[currentIndex].setEnabled(true);
currentIndex = (int) v.getTag();
}
//使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發
@Override
public boolean onDown(MotionEvent e) {
return false;
}
//使用者輕觸觸控式螢幕,尚未鬆開或拖動,由一個1個MotionEvent ACTION_DOWN觸發
//注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態
@Override
public void onShowPress(MotionEvent e) {
}
//使用者(輕觸觸控式螢幕後)鬆開,由一個1個MotionEvent ACTION_UP觸發
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
//使用者按下觸控式螢幕,並拖動,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE觸發
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
//使用者長按觸控式螢幕,由多個MotionEvent ACTION_DOWN觸發
@Override
public void onLongPress(MotionEvent e) {
}
//使用者按下觸控式螢幕、快速移動後鬆開,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE,1個ACTION_UP觸發
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e2.getX() - e1.getX() > 120) {
//為了避免能夠一直向右滑動
if (viewFlipper.getDisplayedChild() != 0) {
//向右滑動,設定滑動動畫
viewFlipper.setInAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
R.anim.push_right_in));
viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
R.anim.push_right_out));
//這個要判斷,不然就會跳到第一個
viewFlipper.showPrevious();
//當前頁卡被選擇時,viewFlipper.getDisplayedChild()為當前頁數
points[viewFlipper.getDisplayedChild()].setEnabled(false);//不可點選
points[currentIndex].setEnabled(true);//恢復之前頁面狀態
currentIndex = viewFlipper.getDisplayedChild();
return true;
}
} else if (e2.getX() - e1.getX() < 120) {
//為了避免能夠一直向左滑動
if (viewFlipper.getDisplayedChild() != viewFlipper.getChildCount() - 1) {
//向左滑動,設定滑動動畫
viewFlipper.setInAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
R.anim.push_left_in));
viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(ViewFlipperActivity.this,
R.anim.push_left_out));
//這個要判斷,不然就會跳到最後一個
viewFlipper.showNext();
//當前頁卡被選擇時,viewFlipper.getDisplayedChild()為當前頁數
points[viewFlipper.getDisplayedChild()].setEnabled(false);//不可點選
points[currentIndex].setEnabled(true);//恢復之前頁面狀態
currentIndex = viewFlipper.getDisplayedChild();
return true;
}
}
return false;
}
//使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.gestureDetector.onTouchEvent(event);
}
}
解釋:這裡我用ViewFlipper實現這個啟動頁的功能,一開始以為應該會比ViewPager實現容易,但是自己後來弄了一下,感覺自己還是不怎麼能弄出來。我來講一下有幾處要注意的。
1、使用ViewFlipper來實現啟動頁功能,需要使用手勢。讓類繼承GestureDetector.OnGestureListener介面,實現一些必要的方法。主要是onFling()方法。
2、為了讓ViewFlipper不能一直的滑動下去。需要判斷是不是第一個和最後一個,使用 if (viewFlipper.getDisplayedChild() != 0)判斷是不是第一個,使用if (viewFlipper.getDisplayedChild() != viewFlipper.getChildCount() - 1)判斷是不是最後一個。
3、在滑動了ViewFlipper之後,我們也要考慮和ViewPager相同的兩個問題。ViewFlipper滑動帶動指示器,指示器點選帶動ViewFlpper。
使用
//當前頁卡被選擇時,viewFlipper.getDisplayedChild()為當前頁數
points[viewFlipper.getDisplayedChild()].setEnabled(false);//不可點選
points[currentIndex].setEnabled(true);//恢復之前頁面狀態
currentIndex = viewFlipper.getDisplayedChild();
來使ViewFlipper滑動,帶動指示器的滑動。
使用
//點選小點,改變小點的狀態,並且改變viewFlipper中子view的顯示
viewFlipper.setDisplayedChild((int) v.getTag());
points[(int) v.getTag()].setEnabled(false);
points[currentIndex].setEnabled(true);
currentIndex = (int) v.getTag();
來點選指示器,帶動ViewFlipper的跳轉。
注意:可能是方法不同的原因,在ViewPager中,setCurrentItem(int item)方法就可以直接呼叫第幾個介面,然後再觸發onPageSelected(int position)方法,使得指示器按鈕變化。而在ViewFlipper中,setDisplayedChild(int childid)方法只能呼叫第幾個介面,不能觸發onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)方法,onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)方法只能通過滑動來獲得。
4、需要注意的是,使用手勢的時候,一定要實現這個方法,不然手勢不能生效。原因,查了好多,都是說未知。
//使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發
@Override
public boolean onTouchEvent(MotionEvent event) {
return this.gestureDetector.onTouchEvent(event);
}