開頭:
在做android開發的時候,我們經常會遇到這樣的布局,上面是一個圖片輪播圖,下面是一些列表的項目。很多新聞app,視頻類app都采用這樣的布局。起初的時候
由於沒有很多參考,我自己想到了一種實現方式,就是用scrollview作為外面最大的布局,然后里面嵌套viewpager和listview,但是我現在非常不推薦這種方式,一方面由於這種方式
需要將listview完全展開,缺少了getview函數中應該有的復用與優化。而且結構嵌套復雜。經過一番查找與學習,學習到兩種比較規范或者結構比較清晰的實現方式,那么下面,我來分別介紹
一下這兩種方式。
轉載請注明出處 http://www.cnblogs.com/gaoteng/p/4162749.html www.gaotenglife.com
方法一:listview的addheadview方法
首先我們新建一個布局文件,存放listview,如下
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="16dp" android:text="first" /> <ListView android:id="@+id/list_view_first" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/textView1" /> </RelativeLayout>
布局很簡單,里面就主要有一個listview。
然后頂部的輪播圖,我們采用viewpager的方式去實現。同樣新建一個布局,里面存放viewpager
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="100dp" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/headviewpager" android:layout_width="match_parent" android:layout_height="100dp" /> </LinearLayout>
通過上面兩步,我們已經建立好了用到的布局文件,很簡單。
那么接下來,viewpager需要一個adapter來填充數據,這里我們的數據,就是一些圖片,讓viewpager去展示。
我們再新建一個自己的viewpageradapter,這個adapger在后面的另一種實現方式中也會用到,所以,單獨建立一個文件存放。
下面是代碼:
/** * * @author xuelang www.gaotenglife.com * */ public class ViewPageAdapter extends PagerAdapter { List<ImageView> list = null;//我們用一個list存放所有的imageview public ViewPageAdapter (List<ImageView> _list) { list = _list; } @Override public void destroyItem(View container, int position, Object object) { // TODO Auto-generated method stub ((ViewPager)container).removeView(list.get(position)); } @Override public Object instantiateItem(View container, int position) { // TODO Auto-generated method stub ((ViewPager) container).addView(list.get(position)); return list.get(position); } @Override public int getCount() { // TODO Auto-generated method stub return list.size();//返回數據的個數 } @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return (arg0 == arg1);//這句話,比較重要,加上之后才能正確顯示 } }
上面的代碼很簡單,是一個pageadapter的標准用法。這樣我們基本上所有的准備工作已經完成了,最后一步,就是我們把viewpager通過listview的addheadview方式加入到listview的頭上。
下面便是acitivity中的主要代碼(在文章的結尾,我會附加源代碼的下載地址,有需要的可以下載詳細看)
private void initHeadView() { listview = (ListView)this.findViewById(R.id.list_view_first); View view = LayoutInflater.from(this).inflate(R.layout.head_viewpager, null); ViewPager viewpager = (ViewPager)view.findViewById(R.id.headviewpager); List<ImageView> listtemp = new ArrayList<ImageView>(); for(int i = 0;i<4;i++) { ImageView img = new ImageView(this); img.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,100)); img.setScaleType(ScaleType.FIT_XY); img.setBackgroundResource(R.drawable.ic_launcher); listtemp.add(img); } ViewPageAdapter viewadapter = new ViewPageAdapter(listtemp); listview.addHeaderView(view); listview.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data)); viewpager.setAdapter(viewadapter); }
簡單解釋一下上面的內容:
LayoutInflater.from(this).inflate(R.layout.head_viewpager, null);
這句話將我們之前建立好的布局文件載入進來
然后通過for循環初始化imageview的list
for(int i = 0;i<4;i++)
....
最重要的就是這句話
listview.addHeaderView(view);
將初始化好的view添加到head上面。至此我們的第一種方法,就已經完成,是不是很簡單。
方法二:viewpager作為listview的一個item
這種方式是我受到別的文章的啟發,一個listview可以指定它每一個item為不同的布局類型,從而實現listview的多元化,那么我們同樣可以利用這個方法。
把listview的第一項初始化為viewpager,這樣不也就實現了頂部時viewpager的效果了嘛。說干就干,代碼繼續碼起來。
在這種方式中,最主要的內容部分就在listview的adapter中。所以我也就主要介紹這一個adapter,我相信,看懂了這個adapter,那么其他部分,自然很容易理解了。
在官方api中提供了下面這兩個方法,這也是今天實現這個功能主要的兩個方法。
getViewTypeCount //用來返回在這個listview中有幾種不同的item類型
getItemViewType //用來返回某個具體位置上面的item的類型()
@Override public int getItemViewType(int position) { // TODO Auto-generated method stub return position>0?0:1; } @Override public int getViewTypeCount() { // TODO Auto-generated method stub return 2; }
由於我們只做一個簡單演示,所以就分為兩種類型,一種是viewpager類型的item,另一種是不同類型的item,所以當position大於0,也就是我們的普通類型,position等於0,就是第一項,也就是viewpager。
接下來便是這個功能最最重要的一個函數getview,因為我們將在這個函數中做所有的顯示工作。
我們先把代碼附上,然后詳細介紹。
@Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub View view = null; if(getItemViewType(position) == 0)// { ViewHolder holder = null; if(convertView==null) { view = m_inflater.inflate(R.layout.list_item, null); holder = new ViewHolder(); holder.textView = (TextView)view.findViewById(R.id.list_item); view.setTag(holder); } else { view = convertView; holder = (ViewHolder)view.getTag(); } holder.textView.setText(position+""); } else if(getItemViewType(position) == 1)//如果是頂部viewpager { ViewPagerHolder holder = null; if(convertView==null) { view = m_inflater.inflate(R.layout.head_viewpager, null); holder = new ViewPagerHolder(); holder.viewPager = (ViewPager)view.findViewById(R.id.headviewpager); List<ImageView> listtemp = new ArrayList<ImageView>(); for(int i = 0;i<4;i++) { ImageView img = new ImageView(SecondActivity.this); img.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,100)); img.setScaleType(ScaleType.FIT_XY); img.setBackgroundResource(R.drawable.ic_launcher); listtemp.add(img); } ViewPageAdapter viewadapter = new ViewPageAdapter(listtemp); holder.viewPager.setAdapter(viewadapter); view.setTag(holder); } else { view = convertView; holder = (ViewPagerHolder)view.getTag(); } } return view; } }
下面我來詳細說明一下上面的函數。其實基本的骨架大家應該都能看懂。使用了listview復用的概念。
if(getItemViewType(position) == 1)
通過這個判斷目前需要顯示的view是哪種類型。那么這里如果是1,就是我們的viewpager項,
然后再判斷convertView是否為空,來決定是否復用。
如果為空,說明在內存中沒有保留過,於是通過LayoutInflate創建view,同時我們創建了一個
holder = new ViewPagerHolder();
緩沖,用來保存之前創建好的布局,以便下次使用。
然后創建好viewpager的數據List<ImageView> data,使用前面的ViewPageAdapter,將數據與viewpager綁定,然后用settag的方式,把holder數據,保存到view里面。
當判斷convertview不為空的時候,我們從convertview中取出tag,轉換為holder,然后就又得到了viewpager對象了。
這是if(getItemViewType(position) == 1)的情況。
那么if(getItemViewType(position) == 0)的情況就更簡單了,基本上和這類似。
也是復用了convertview,然后通過holder的方式,將view對象保存起來,不用下一次通過findviewbyid的方式來查找了,提高了效率。
轉載請注明出處 http://www.cnblogs.com/gaoteng/p/4162749.html www.gaotenglife.com
下面附上源碼下載地址
csdn資源
http://download.csdn.net/detail/gaotengguojianhong/8308407
github資源
https://github.com/langxuelang/ListViewDemo