Android UI 之 Tab類型介面總結,androidui
轉載請註明出處:http://blog.csdn.net/crazy1235/article/details/42678877
Android 程式中實現Tab類型介面很常見,本人在做項目的時候也經常用到,所以想在這裡總結一下,實現tab類型介面的幾種方式,供大家參考。如有不對之處,歡迎大家指正!
一、TabActivity + TabWidget + TabHost.
實現TAB類型介面,首先想到的就是這種方式。但是在API level 13之後官方就不建議使用它了。不過還是在這裡簡單說一下它的使用吧。
使用它的關鍵就是布局檔案了。需要在布局中添加<TabHost>、<TabWidget>、<FrameLayout>這三個控制項,id分別是系統提供的:@android:id/tabhost 、@android:id/tabs 、@android:id/tabcontent 。
<?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="match_parent" android:orientation="vertical" > <TabHost android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent" > <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!-- 可以指定tabwidget的位置 android:layout_alignParentBottom="true" --> <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="false" > </TabWidget> <FrameLayout android:id="@android:id/tabcontent" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@android:id/tabs" > <LinearLayout android:id="@+id/tab1" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#DEB887" android:orientation="vertical" > </LinearLayout> <LinearLayout android:id="@+id/tab2" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#BCEE68" android:orientation="vertical" > </LinearLayout> <LinearLayout android:id="@+id/tab3" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#7D9EC0" android:orientation="vertical" > </LinearLayout> </FrameLayout> </RelativeLayout> </TabHost></LinearLayout>
一個linearlayout對應一個tab頁面的布局。
tabHost = getTabHost();tabHost.addTab(tabHost.newTabSpec("111").setIndicator("", getResources().getDrawable(R.drawable.wuyong)).setContent(R.id.tab1));tabHost.addTab(tabHost.newTabSpec("222").setIndicator("",getResources().getDrawable(R.drawable.gongsunsheng)).setContent(R.id.tab2));tabHost.addTab(tabHost.newTabSpec("333").setIndicator("", getResources().getDrawable(R.drawable.likui)).setContent(R.id.tab3));tabHost.setBackgroundColor(Color.argb(150, 22, 70, 150));tabHost.setCurrentTab(0);tabHost.setOnTabChangedListener(new OnTabChangeListener() {@Overridepublic void onTabChanged(String tabId) {Toast.makeText(FourthActivity.this, tabId, Toast.LENGTH_SHORT).show();}});
二、ViewPager + PageAdapter
目前最常見的tab介面就是使用viewpager來實現了。
先來說一下viewpager的一般使用步驟:
1. 在布局檔案中添加viewpager控制項
2. 在代碼中設定viewpager適配器,該類繼承與pagerAdapter或它的子類。必須實現以下四個方法:
(1)getCount()
(2)instantiateItem()
(3)destoryItem()
(4)isViewFromObject()
3. 初始化viewpager控制項,設定監聽器
4. 設定監聽事件(setOnPageChangeListener)
下面看一下這種方式的:
主要的功能代碼如下:
private void init() {viewPager = (ViewPager) findViewById(R.id.first_vp);LayoutInflater inflater = LayoutInflater.from(this);View view1 = inflater.inflate(R.layout.first_layout1, null);View view2 = inflater.inflate(R.layout.first_layout2, null);View view3 = inflater.inflate(R.layout.first_layout3, null);list.add(view1);list.add(view2);list.add(view3);viewPager.setAdapter(pagerAdapter);viewPager.setOnPageChangeListener(new OnPageChangeListener() {@Overridepublic void onPageSelected(int arg0) {setDots(arg0);}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {}@Overridepublic void onPageScrollStateChanged(int arg0) {}});}
private PagerAdapter pagerAdapter = new PagerAdapter() {
<span style="white-space:pre"></span>//官方建議這麼寫@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;} <span style="white-space:pre"></span>//返回一共有多少個介面@Overridepublic int getCount() {return list.size();}<span style="white-space:pre"></span>//執行個體化一個item@Overridepublic Object instantiateItem(ViewGroup container, int position) {container.addView(list.get(position));return list.get(position);} <span style="white-space:pre"></span>//銷毀一個item@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView(list.get(position));}}; 適配器中必須要實現以上的四個方法。
如果只有這幾個頁面,互動性肯定是不好的,所以需要添加“指標”,用來標識當前的頁面是哪一個!我在這裡用點來實現。就像顯示的那樣。
/** * 初始化底部的點 */private void initDots() {pointLayout = (LinearLayout) findViewById(R.id.point_layout);dots = new ImageView[list.size()];for (int i = 0; i < list.size(); i++) {dots[i] = (ImageView) pointLayout.getChildAt(i);}currentIndex = 0;dots[currentIndex].setBackgroundResource(R.drawable.dian_down);}/** * 當滾動的時候更換點的背景圖 */private void setDots(int position) {if (position < 0 || position > list.size() - 1|| currentIndex == position) {return;}dots[position].setBackgroundResource(R.drawable.dian_down);dots[currentIndex].setBackgroundResource(R.drawable.dian);currentIndex = position;} 重點就是頁面切換之後,點也要切換。這時候就用到了OnPageChangeListener中的onPageSelected(int arg0)這個方法了。
@Overridepublic void onPageSelected(int arg0) {setDots(arg0);}
三、Fragment + FragmentManager
fragment相信大家在項目中肯定都用過。這個方法主要就是利用fragmentManager對fragment的交易管理功能。
// 三個選項卡private LinearLayout tab1Layout, tab2Layout, tab3Layout;// 預設選中第一個tabprivate int index = 1;// fragment管理類private FragmentManager fragmentManager;// 三個fragmentprivate Fragment tab1Fragment, tab2Fragment, tab3Fragment;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);fragmentManager = getSupportFragmentManager();init();}/** * 初始化控制項 */private void init() {tab1Layout = (LinearLayout) findViewById(R.id.tab1_layout);tab2Layout = (LinearLayout) findViewById(R.id.tab2_layout);tab3Layout = (LinearLayout) findViewById(R.id.tab3_layout);tab1Layout.setOnClickListener(this);tab2Layout.setOnClickListener(this);tab3Layout.setOnClickListener(this);//setDefaultFragment();}/** * 設定預設顯示的fragment */private void setDefaultFragment() {FragmentTransaction transaction = fragmentManager.beginTransaction();tab1Fragment = new Tab1Fragment();transaction.replace(R.id.content_layout, tab1Fragment);transaction.commit();}/** *切換fragment * @param newFragment */private void replaceFragment(Fragment newFragment) {FragmentTransaction transaction = fragmentManager.beginTransaction();if (!newFragment.isAdded()) {transaction.replace(R.id.content_layout, newFragment);transaction.commit();} else {transaction.show(newFragment);}}/** * 改變現象卡的選中狀態 */private void clearStatus() {if (index == 1) {tab1Layout.setBackgroundColor(getResources().getColor(R.color.tab));} else if (index == 2) {tab2Layout.setBackgroundColor(getResources().getColor(R.color.tab));} else if (index == 3) {tab3Layout.setBackgroundColor(getResources().getColor(R.color.tab));}}@Overridepublic void onClick(View v) {clearStatus();switch (v.getId()) {case R.id.tab1_layout:if (tab1Fragment == null) {tab1Fragment = new Tab1Fragment();}replaceFragment(tab1Fragment);tab1Layout.setBackgroundColor(getResources().getColor(R.color.tab_down));index = 1;break;case R.id.tab2_layout:if (tab2Fragment == null) {tab2Fragment = new Tab2Fragment();}replaceFragment(tab2Fragment);tab2Layout.setBackgroundColor(getResources().getColor(R.color.tab_down));index = 2;break;case R.id.tab3_layout:if (tab3Fragment == null) {tab3Fragment = new Tab3Fragment();}replaceFragment(tab3Fragment);tab3Layout.setBackgroundColor(getResources().getColor(R.color.tab_down));index = 3;break;}}
每一個fragment對應一個布局,點擊不同的按鈕來切換頁面。效果如:
四、ViewPager + Fragment + FragmentPagerAdapter
如果想使用fragment的時候又想可以左右滑動,就可以使用這種方式。主要的部分就在viewpager的適配器。它的適配器繼承FragmentPagerAdapter.
package com.tab.view.demo3;import java.util.ArrayList;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentPagerAdapter;public class FragmentAdapter extends FragmentPagerAdapter {private ArrayList<Fragment> list;public FragmentAdapter(FragmentManager fm, ArrayList<Fragment> list) {super(fm);this.list = list;}@Overridepublic Fragment getItem(int arg0) {return list.get(arg0);}@Overridepublic int getCount() {return list.size();}}
需要傳入FragmentManager對象和一個存放fragment的list對象。
/** * 初始化viewpager */private void initViewPager() {viewPager = (ViewPager) findViewById(R.id.third_vp);fragmentsList = new ArrayList<>();Fragment fragment = new Tab1Fragment();fragmentsList.add(fragment);fragment = new Tab2Fragment();fragmentsList.add(fragment);fragment = new Tab3Fragment();fragmentsList.add(fragment);viewPager.setAdapter(new FragmentAdapter(getSupportFragmentManager(),fragmentsList));viewPager.setCurrentItem(0);viewPager.setOnPageChangeListener(this);}
對button添加點擊事件。
@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.tab1_tv:viewPager.setCurrentItem(0);break;case R.id.tab2_tv:viewPager.setCurrentItem(1);break;case R.id.tab3_tv:viewPager.setCurrentItem(2);break;}}
我在布局檔案中添加了一個imageview作為指標。如果想第一種tab類型介面的實現方式那樣在onPageSelected()方法中進行設定,效果是只能當頁面完全切換過來之後才能把指標移動過去。要想實現滑動頁面的時候同時移動指標,就需要在onPageScrolled()方法中進行設定。
@Overridepublic void onPageScrolled(int position, float positionOffset,int positionOffsetPixels) {offset = (screen1_3 - cursorImg.getLayoutParams().width) / 2;Log.d("111", position + "--" + positionOffset + "--"+ positionOffsetPixels);final float scale = getResources().getDisplayMetrics().density;if (position == 0) {// 0<->1lp.leftMargin = (int) (positionOffsetPixels / 3) + offset;} else if (position == 1) {// 1<->2lp.leftMargin = (int) (positionOffsetPixels / 3) + screen1_3 +offset;}cursorImg.setLayoutParams(lp);currentIndex = position;}
onPageScrolled中的三個參數比較重要。第一個參數是position。它的含義是表示當前顯示的介面中的第一個介面。意思就是的當滑動的時候,有可能出現兩個介面,position指的是左邊的介面。第二個參數是positionOffset指的是位移量的比例,取值範圍是[0, 1)。第三個參數是positionOffsetPixels是指位移的像素值。後兩個參數都相對頁面(一個page)來說的。
我之前有看到過設定指標的時候用的前兩個參數的,我也試了一下,OK的。不過感覺比較複雜,看了一下官方api,用第三個參數更簡單。關鍵就是理解第一個參數position。用這種方法我只在代碼裡有兩個判斷就可以完成了。
如下:
五、Viewpager + PagerTitleStrip / PagerTabStrip
這種方式沒有上一種效果好看,而且標題變動。看一下:
布局檔案:
<?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="match_parent" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/fifth_vp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" > <android.support.v4.view.PagerTabStrip android:id="@+id/fifth_strip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top" android:background="#7EC0EE" android:padding="10dip" /> </android.support.v4.view.ViewPager></LinearLayout>
先來說一下PagerTitleStrip和PagerTabStrip的區別:PagerTitleStrip沒有指標,只有標題,且標題沒有響應事件;而PagerTabStrip是帶有指標的,當然也有標題,具有相應事件。二者的實現只在布局檔案中有區別,只需要把android.support.v4.view.PagerTabStrip改成android.support.v4.viewPagerTitleStrip即可。
代碼中需要注意的就是,在適配器中重寫getPageTitle(int)方法來顯示標題。
PagerAdapter pagerAdapter = new PagerAdapter() { //此處省略其他的方法
// 重寫此方法即可顯示標題@Overridepublic CharSequence getPageTitle(int position) {return titleList.get(position);}};
總結:
我目前所遇到的tab類型介面的實現方式就是這麼多了,若果大家有其他的實現方式,請留言。如果我寫的有誤,請留言指正,共同進步!謝謝!
Demo:http://download.csdn.net/detail/crazy1235/8358671