在这部分的讲解中,我们使用了Android提供另一个非常有用的控件ViewPager。使用这个控件,需要用到google提到的一个包——android-support-v4.jar,这个包中包含了一些非常有用的类,其中就是ViewPager类来实现页面之间的切换操作,关于android-support-v4.jar的详细信息,大家可以访问google官方网站:
http://developer.android.com/sdk/compatibility-library.html。
具体的把Android提供的android-support-v4.jar导入工程,并add build path的方法这里不做介绍,可以参考以上提供的网址,里面会有详细的说明,步骤比较简单。
下面通过两个例子来讲解一下比较复杂的滑动界面的实现。
一、Demo1
Demo1实现的效果是我们在浏览新闻网页时经常会看到的,屏幕的上半部分是图片,下半部分是文字的介绍,而顶部是一个导航的工具栏可以供用户选择退出或者回到主菜单等。用户通过左右的滑动屏幕,实现翻页的效果。而在屏幕的最底部,会有对当前所处页面的指示标记。
主布局文件main.xml的内容如下:
[代码]xml代码:
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
02 | < FrameLayout xmlns:android = "http://schemas.android.com/apk/res/android" |
03 | android:layout_width = "fill_parent" |
04 | android:layout_height = "fill_parent" |
05 | android:orientation = "vertical" > |
06 | |
07 | < LinearLayout |
08 | android:layout_width = "fill_parent" |
09 | android:layout_height = "wrap_content" |
10 | android:orientation = "vertical" > |
11 | < include android:id = "@+id/item_header" |
12 | layout = "@layout/item_header" /> |
13 | < android.support.v4.view.ViewPager |
14 | android:id = "@+id/myviewpager" |
15 | android:layout_width = "fill_parent" |
16 | android:layout_height = "wrap_content" /> |
17 | </ LinearLayout > |
18 | |
19 | < LinearLayout |
20 | android:layout_width = "fill_parent" |
21 | android:layout_height = "fill_parent" |
22 | android:orientation = "vertical" > |
23 | |
24 | < RelativeLayout |
25 | android:layout_width = "fill_parent" |
26 | android:layout_height = "wrap_content" |
27 | android:orientation = "vertical" > |
28 | |
29 | < LinearLayout |
30 | android:id = "@+id/mybottomviewgroup" |
31 | android:layout_width = "fill_parent" |
32 | android:layout_height = "wrap_content" |
33 | android:layout_alignParentBottom = "true" |
34 | android:layout_marginBottom = "40dp" |
35 | android:gravity = "center_horizontal" |
36 | android:orientation = "horizontal" > |
37 | |
38 | </ LinearLayout > |
39 | |
40 | </ RelativeLayout > |
41 | </ LinearLayout > |
42 | |
43 | </ FrameLayout > |
最外层是LinearLayout,其中包括两个Linearlayout,第一个LinearLayout是显示新闻的主界面,而第二个LinearLayout是为了在底部存放指示当前界面的标记图片。值得注意的是第一个LinearLayout中包括又包括两部分,一个是通过include引入的item_header视图,一个是ViewPager控件,在这里还要注意ViewPager空间的布局方式。代码如下:
[代码]xml代码:
01 | < LinearLayout |
02 | android:layout_width = "fill_parent" |
03 | android:layout_height = "wrap_content" |
04 | android:orientation = "vertical" > |
05 | < include android:id = "@+id/item_header" |
06 | layout = "@layout/item_header" /> |
07 | < android.support.v4.view.ViewPager |
08 | android:id = "@+id/myviewpager" |
09 | android:layout_width = "fill_parent" |
10 | android:layout_height = "wrap_content" /> |
11 | </ LinearLayout > |
另外,在layout文件夹下还定义了item01——item06六个布局文件作为ViewPager的六个页面,在JAVA代码中会把它们分别添加进ViewPager。Item_header.xml布局定义了屏幕上方的导航栏,通过include的方式引入了main.xml布局文件。
Demo1的JAVA代码如下:
[代码]java代码:
001 | package com.devdiv.test.ui_test_viewpager; |
002 |
003 | import java.util.ArrayList; |
004 | import android.app.Activity; |
005 | import android.content.Context; |
006 | import android.os.Bundle; |
007 | import android.os.Parcelable; |
008 | import android.support.v4.view.PagerAdapter; |
009 | import android.support.v4.view.ViewPager; |
010 | import android.support.v4.view.ViewPager.OnPageChangeListener; |
011 | import android.view.LayoutInflater; |
012 | import android.view.View; |
013 | import android.view.ViewGroup; |
014 | import android.view.ViewGroup.LayoutParams; |
015 | import android.view.Window; |
016 | import android.widget.ImageView; |
017 | public class UI_Test_ViewPagerActivity extends Activity { |
018 | |
019 | private ViewPager mViewPager; |
020 | private ArrayList<View> mPageViews; |
021 | private ImageView mImageView; |
022 | private ImageView[] mImageViews; |
023 | |
024 | //该应用的主布局LinearLayout |
025 | private ViewGroup mainViewGroup; |
026 | //主布局底部指示当前页面的小圆点视图,LinearLayout |
027 | private ViewGroup indicatorViewGroup; |
028 | |
029 | //定义LayoutInflater |
030 | LayoutInflater mInflater; |
031 | |
032 | /** Called when the activity is first created. */ |
033 | @Override |
034 | public void onCreate(Bundle savedInstanceState) { |
035 | super .onCreate(savedInstanceState); |
036 | //setContentView(R.layout.main); |
037 | |
038 | //设置窗口无标题 |
039 | requestWindowFeature(Window.FEATURE_NO_TITLE); |
040 | |
041 | //mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
042 | mInflater = getLayoutInflater(); |
043 | |
044 | mPageViews = new ArrayList<View>(); |
045 | mPageViews.add(mInflater.inflate(R.layout.item01, null )); |
046 | mPageViews.add(mInflater.inflate(R.layout.item02, null )); |
047 | mPageViews.add(mInflater.inflate(R.layout.item03, null )); |
048 | mPageViews.add(mInflater.inflate(R.layout.item04, null )); |
049 | mPageViews.add(mInflater.inflate(R.layout.item05, null )); |
050 | mPageViews.add(mInflater.inflate(R.layout.item06, null )); |
051 | |
052 | mImageViews = new ImageView[mPageViews.size()]; |
053 | |
054 | mainViewGroup = (ViewGroup) mInflater.inflate(R.layout.main, null ); |
055 | |
056 | mViewPager = (ViewPager) mainViewGroup.findViewById(R.id.myviewpager); |
057 | indicatorViewGroup = (ViewGroup) mainViewGroup.findViewById(R.id.mybottomviewgroup); |
058 | |
059 | for ( int i = 0 ; i < mImageViews.length; i++) { |
060 | mImageView = new ImageView(UI_Test_ViewPagerActivity. this ); |
061 | mImageView.setLayoutParams( new LayoutParams( 20 , 20 )); |
062 | mImageView.setPadding( 20 , 0 , 20 , 0 ); |
063 | |
064 | if (i == 0 ) { |
065 | mImageView.setBackgroundResource(R.drawable.page_indicator_focused); |
066 | } else { |
067 | mImageView.setBackgroundResource(R.drawable.page_indicator); |
068 | } |
069 | |
070 | mImageViews[i] = mImageView; |
071 | |
072 | //把指示作用的远点图片加入底部的视图中 |
073 | indicatorViewGroup.addView(mImageViews[i]); |
074 | } |
075 | |
076 | //注意这两种用法的区别,前者无法正常显示!! |
077 | //setContentView(R.layout.main); |
078 | setContentView(mainViewGroup); |
079 | |
080 | |
081 | mViewPager.setAdapter( new MyPagerAdapter()); |
082 | mViewPager.setOnPageChangeListener( new OnPageChangeListener() { |
083 | |
084 | @Override |
085 | public void onPageSelected( int arg0) { |
086 | // TODO Auto-generated method stub |
087 | for ( int i = 0 ; i < mImageViews.length; i++) { |
088 | if (i == arg0) { |
089 | mImageViews[i].setBackgroundResource(R.drawable.page_indicator_focused); |
090 | } else { |
091 | mImageViews[i].setBackgroundResource(R.drawable.page_indicator); |
092 | } |
093 | } |
094 | } |
095 | |
096 | @Override |
097 | public void onPageScrolled( int arg0, float arg1, int arg2) { |
098 | // TODO Auto-generated method stub |
099 | |
100 | } |
101 | |
102 | @Override |
103 | public void onPageScrollStateChanged( int arg0) { |
104 | // TODO Auto-generated method stub |
105 | |
106 | } |
107 | }); |
108 | |
109 | } |
110 | |
111 | class MyPagerAdapter extends PagerAdapter { |
112 | @Override |
113 | public int getCount() { |
114 | return mPageViews.size(); |
115 | } |
116 | |
117 | @Override |
118 | public boolean isViewFromObject(View arg0, Object arg1) { |
119 | return arg0 == arg1; |
120 | } |
121 | |
122 | @Override |
123 | public int getItemPosition(Object object) { |
124 | // TODO Auto-generated method stub |
125 | return super .getItemPosition(object); |
126 | } |
127 | |
128 | @Override |
129 | public void destroyItem(View arg0, int arg1, Object arg2) { |
130 | // TODO Auto-generated method stub |
131 | ((ViewPager) arg0).removeView(mPageViews.get(arg1)); |
132 | } |
133 | |
134 | @Override |
135 | public Object instantiateItem(View arg0, int arg1) { |
136 | // TODO Auto-generated method stub |
137 | ((ViewPager) arg0).addView(mPageViews.get(arg1)); |
138 | return mPageViews.get(arg1); |
139 | } |
140 | |
141 | @Override |
142 | public void restoreState(Parcelable arg0, ClassLoader arg1) { |
143 | // TODO Auto-generated method stub |
144 | |
145 | } |
146 | |
147 | @Override |
148 | public Parcelable saveState() { |
149 | // TODO Auto-generated method stub |
150 | return null ; |
151 | } |
152 | |
153 | @Override |
154 | public void startUpdate(View arg0) { |
155 | // TODO Auto-generated method stub |
156 | |
157 | } |
158 | |
159 | @Override |
160 | public void finishUpdate(View arg0) { |
161 | // TODO Auto-generated method stub |
162 | |
163 | } |
164 | |
165 | } |
166 | |
167 | } |
其中,需要注意的是在自定义MyPagerAdapter继承自PagerAdapter,需要重写其中的一些重要方法,可以类比BaseAdapter的实现便于理解,具体实现参考API文档。
[代码]java代码:
01 | mImageViews = new ImageView[mPageViews.size()]; |
02 | |
03 | mainViewGroup = (ViewGroup) mInflater.inflate(R.layout.main, null ); |
04 | |
05 | mViewPager = (ViewPager) mainViewGroup.findViewById(R.id.myviewpager); |
06 | indicatorViewGroup = (ViewGroup) mainViewGroup.findViewById(R.id.mybottomviewgroup); |
07 | |
08 | for ( int i = 0 ; i < mImageViews.length; i++) { |
09 | mImageView = new ImageView(UI_Test_ViewPagerActivity. this ); |
10 | mImageView.setLayoutParams( new LayoutParams( 20 , 20 )); |
11 | mImageView.setPadding( 20 , 0 , 20 , 0 ); |
12 | |
13 | if (i == 0 ) { |
14 | mImageView.setBackgroundResource(R.drawable.page_indicator_focused); |
15 | } else { |
16 | mImageView.setBackgroundResource(R.drawable.page_indicator); |
17 | } |
18 | |
19 | mImageViews[i] = mImageView; |
20 | |
21 | //把指示作用的远点图片加入底部的视图中 |
22 | indicatorViewGroup.addView(mImageViews[i]); |
23 | } |
根据mPageViews的大小初始化ImageViews,也就是说ViewPager中存在几个Page就初始化几个圆点的图片进行相应的指示。并且根据位置,设置圆点的不同状态,出事情况下显示第一个Page,因此第一个圆点的图片是focused的状态。最后,通过indicatorViewGroup.addView(mImageViews[i])把所有圆点的图片添加到布局中,在屏幕上显示。
底部圆点图片初始化并加入布局后,需要给ViewPager设置Adapter,这里使用的是我们自定义的MyPagerAdapter,然后执行setContentView操作。
最后,为了是底部的圆点视图具有指示作用,需要为ViewPager设置监听器,来根据ViewPager的不同状态,改变底部圆点视图的状态。代码如下:
[代码]java代码:
01 | mViewPager.setOnPageChangeListener( new OnPageChangeListener() { |
02 | |
03 | @Override |
04 | public void onPageSelected( int arg0) { |
05 | // TODO Auto-generated method stub |
06 | for ( int i = 0 ; i < mImageViews.length; i++) { |
07 | if (i == arg0) { |
08 | mImageViews[i].setBackgroundResource(R.drawable.page_indicator_focused); |
09 | } else { |
10 | mImageViews[i].setBackgroundResource(R.drawable.page_indicator); |
11 | } |
12 | } |
13 | } |
14 | |
15 | @Override |
16 | public void onPageScrolled( int arg0, float arg1, int arg2) { |
17 | // TODO Auto-generated method stub |
18 | |
19 | } |
20 | |
21 | @Override |
22 | public void onPageScrollStateChanged( int arg0) { |
23 | // TODO Auto-generated method stub |
24 | |
25 | } |
26 | }); |
27 | <font style= "BACKGROUND-COLOR: #ffffff" face= "Tahoma" ></font> |
Demo1运行效果如下:
图1 Demo1运行效果1
图2 Demo1运行效果2
二、Demo2
Demo2同样实现了左右滑动的效果,不过我们在不同的页面使用了不同的布局,这在实际的应用中也是很常见的。我们同样使用了ViewPager控件,具体方法和Demo1基本相同。
不同在于,我们在两个页面中分别使用了ListView中GridView视图,并在代码中为它们分别绑定了不同的Adapter。ListView使用了简单的ArrayAdapter,显示一组数据。GridView使用了自定义的Adapter。
由于Demo2和Demo1的内容非常相似,我们就不再展开分析,读者可以下载代码查看详细内容。
Demo2运行效果如下:
图3 Demo2运行效果1
图4 Demo2运行效果2
Demo1源代码下载:
UI_Test_ViewPager.rar
Demo2源代码下载:
UI_Test_ViewPager3.rar