1. 程式人生 > >android TAb分頁選單實現總結

android TAb分頁選單實現總結

      首先說明的是,我們做APP開發,Tab分頁不管是頂部還是底部,都是必不可少的,網上也有太多太多的實現方式了,我在這裡總結一下:

      第一種方式:TabHost原始方式:(連結另一篇文章

      這裡實現的是底部選單:

      佈局檔案:(我們通過RelativeLayout 可以把TabWidget定位在底部)

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:padding="3dp" >

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1" >
        </FrameLayout>

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@android:id/tabcontent"
            android:background="@drawable/tabbar_bg" />
    </RelativeLayout>

</TabHost>

在這裡我們將說明一下:之前我是獲取到TabWidget的view試圖及內部icon和title,然後控制實現其效果,但是我們也可以用另外一種方式,也就是我們呼叫TabHost.TabSpec 的setIndicator(View view);這個方法,我們可以定製顯示的view,

程式碼片段:

/***
	 * 建立footerview
	 */
	public void createFooterView() {
		tabHost = getTabHost(); // The activity TabHost

		view = new TabView(this, R.drawable.tabbar_icon_home,
				R.drawable.tabbar_icon_home_selecotr);
		view.setBackgroundDrawable(this.getResources().getDrawable(
				R.drawable.footer_view_selector));
		intent = new Intent(MainActivity.this, HomeActivity.class);
		spec = tabHost.newTabSpec("num1").setIndicator(view).setContent(intent);
		tabHost.addTab(spec);

		view = new TabView(this, R.drawable.tabbar_icon_search,
				R.drawable.tabbar_icon_search_selecotr);
		view.setBackgroundDrawable(this.getResources().getDrawable(
				R.drawable.footer_view_selector));
		intent = new Intent(MainActivity.this, HomeActivity.class);
		spec = tabHost.newTabSpec("num2").setIndicator(view).setContent(intent);
		tabHost.addTab(spec);

		view = new TabView(this, R.drawable.tabbar_icon_cart,
				R.drawable.tabbar_icon_cart_selector);
		view.setBackgroundDrawable(this.getResources().getDrawable(
				R.drawable.footer_view_selector));
		intent = new Intent(MainActivity.this, HomeActivity.class);
		spec = tabHost.newTabSpec("num3").setIndicator(view).setContent(intent);
		tabHost.addTab(spec);

		view = new TabView(this, R.drawable.tabbar_icon_more,
				R.drawable.tabbar_icon_more_selecotr);
		view.setBackgroundDrawable(this.getResources().getDrawable(
				R.drawable.footer_view_selector));
		intent = new Intent(MainActivity.this, HomeActivity.class);
		spec = tabHost.newTabSpec("num4").setIndicator(view).setContent(intent);
		tabHost.addTab(spec);
	}
/***
	 * 自定義view
	 * 
	 */
	class TabView extends LinearLayout {
		ImageView imageView;

		public TabView(Context c, int drawable, int drawableselec) {
			super(c);
			imageView = new ImageView(c);
			// 可以定製點選後狀態
			StateListDrawable listDrawable = new StateListDrawable();
			// 未選
			listDrawable.addState(SELECTED_STATE_SET, this.getResources()
					.getDrawable(drawableselec));
			// 選擇
			listDrawable.addState(ENABLED_STATE_SET, this.getResources()
					.getDrawable(drawable));
			imageView.setImageDrawable(listDrawable);// 引用 StateListDrawable
			setGravity(Gravity.CENTER);
			addView(imageView);
		}
	}

這樣我們就實現想要的效果了.(建議使用這種方法,我的專案就是用的這個實現的.
如果我是圖示和文字分開的,我們也可以用(RadioButton代替,也許大家都不陌生,一會我簡單介紹下)

          

這個原始碼是因為專案裡面用的。有時間整理下上傳上去,不過我相信大家看過都會做出來的.


第二種方法:GridView+ActivityGroup (圖片 ,文字)
    (為了省事,我把上下tab分頁整理到一個demo裡面了.)
    這個的佈局檔案我就不顯示了,因為比較簡單,我們還是來看程式碼吧.

程式碼片段:  

/***
 * 介面卡
 * 
 * @author Administrator
 * 
 */
public class ImageAdapter extends BaseAdapter {

	private Context mContext;
	private ImageTextButton[] imgItems;
	private int selResId;

	/***
	 * 
	 * @param c
	 * @param picIds
	 * @param titles
	 * @param width
	 * @param height
	 * @param selResId
	 */
	public ImageAdapter(Context c, int[] picIds, String titles[], int width,
			int height, int selResId) {
		mContext = c;
		this.selResId = selResId;
		imgItems = new ImageTextButton[picIds.length];
		for (int i = 0; i < picIds.length; i++) {
			imgItems[i] = new ImageTextButton(mContext);

			imgItems[i]
					.setLayoutParams(new GridView.LayoutParams(width, height));// 設定ImageView寬高
			imgItems[i].setPadding(2, 2, 2, 2);
			// 顯示圖片與文字
			imgItems[i].setImageResource(picIds[i], titles[i]);
		}
	}

	@Override
	public int getCount() {
		return imgItems.length;
	}

	@Override
	public Object getItem(int position) {
		return position;
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	/***
	 * 設定選中後的效果
	 */
	public void SetFocus(int index) {

		for (int i = 0; i < imgItems.length; i++) {
			// 先把所有設為最初狀態
			if (i != index) {
				imgItems[i].setBackgroundResource(0);// 回到最初樣式
			}
		}
		// 選中設定
		imgItems[index].setBackgroundResource(selResId);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ImageTextButton imageView;
		if (convertView == null) {
			imageView = imgItems[position];
		} else {
			imageView = (ImageTextButton) convertView;
		}
		return imageView;
	}

}
在這裡我們用到了自定義控制元件,其實就是把imageview 和textview 整到一起了,
/***
 * 自定義控制元件(圖片文字)
 */
public class ImageTextButton extends LinearLayout {
	private ImageView button = null;
	private TextView text = null;
	private Context context;


	public ImageTextButton(Context context) {
		this(context, null);
		this.context = context;
	}


	public ImageTextButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		LayoutInflater.from(context).inflate(R.layout.imagetextbutton, this,
				true);
		button = (ImageView) this.findViewById(R.id.button);
		text = (TextView) this.findViewById(R.id.btnText);
		text.setSingleLine(true);
	}


	public void setImageResource(int image_id, String title) {
		Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
				image_id);
		button.setBackgroundDrawable(new BitmapDrawable(bitmap));
		text.setText(title);
	}


	public void setImageBitmap(Bitmap bitmap) {
		if (button != null)
			button.setImageBitmap(bitmap);
	}


	public void setBackgroundDrawable(Drawable drawable, int Width, int Hdight) {
		if (button != null) {
			button.setBackgroundDrawable(drawable);
			button.setMinimumHeight(Hdight);
			button.setMinimumWidth(Width);
		}


	}


	public void setText(String title) {
		if (text != null)
			text.setText(title);
	}


	public void setText(int ResID) {
		if (text != null)
			text.setText(ResID);
	}


	public void setWidth(int width) {
		button.setMaxWidth(width);
	}


	public void setHeight(int height) {
		button.setMaxHeight(height);
	}


}
我們只需要在oncreate中呼叫即可:
@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		Navigation_Top_Bar = (GridView) this
				.findViewById(R.id.Navigation_Top_Bar);
		Navigation_Buttom_Bar = (GridView) this
				.findViewById(R.id.Navigation_Buttom_Bar);
		// 獲取顯示寬度
		int width = this.getWindowManager().getDefaultDisplay().getWidth()
				/ topbar_image_array.length;

		topImgAdapter1 = new ImageAdapter(this, topbar_image_array, titles,
				width, 100, R.drawable.cover);

		Init(Navigation_Top_Bar, topImgAdapter1);

		ButtomImgAdapter2 = new ImageAdapter(this, topbar_image_array, titles,
				width, 100, R.drawable.cover);

		Init(Navigation_Buttom_Bar, ButtomImgAdapter2);

	}
這個實現起來有點複雜,不過用習慣了會覺得別有一翻風味的.我之前就一直用這個方法.
在這裡我要說明一點:
imgItems[i].setLayoutParams(new GridView.LayoutParams(width, height));// 設定ImageView寬高
其他的都是細節上的問題,我想你們看過都會ok的.
效果圖:

        

(怎麼樣,效果還不錯吧。就是實現起來有點負責,不過習慣就好.)

  原始碼下載

第三種方法:ActivityGroup+一些TextView佈局.(在這裡我們自定實現動態滾動效果)
                    詳情請檢視前面一片文章:android 分頁Title欄滑塊效果--ActionBar(模擬網易 騰訊等動態效果)
           分頁Tab的實現方法和上面方法類是,都是運用ActivityGroup的性質,而上面是通過GridView生成,而我們這邊是我們自定義View控制元件實現.
          這裡我主要說一下怎樣實現ActionBar:
         程式碼片段:

/***
 * 自定義控制元件
 * 
 * @author zhangjia
 * 
 *         在這裡我要說明一點 我們在建立RectF矩形的時候,
 * 
 *         參照物原點是所在"父控制元件的左上角".
 * 
 */
public class ActionBar extends LinearLayout implements OnClickListener {

	private ImageView tv1;
	private ImageView tv2;
	private ImageView tv3;
	private ImageView tv4;
	private Paint paint;// 畫筆
	private RectF curRectF;// draw當前bar
	private RectF tarRectF;// draw被點選bar

	private final int space_x = 0;// 相當於pading.
	private final int space_y = 0;// 相當於pading
	private final double step = 32;// 速度step.

	
	public ActionBar(Context context) {
		super(context);
	}

	/***
	 * 構造方法
	 * 
	 * @param context
	 * @param attrs
	 */
	public ActionBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		setWillNotDraw(false);
		LayoutInflater.from(context).inflate(R.layout.action_bar, this, true);
		paint = new Paint();
		paint.setAntiAlias(true);
		tv1 = (ImageView) findViewById(R.id.tv1);
		tv2 = (ImageView) findViewById(R.id.tv2);
		tv3 = (ImageView) findViewById(R.id.tv3);
		tv4 = (ImageView) findViewById(R.id.tv4);
		tv1.setOnClickListener(this);
		tv2.setOnClickListener(this);
		tv3.setOnClickListener(this);
		tv4.setOnClickListener(this);
		curRectF = null;
		tarRectF = null;
	}

	/***
	 * invalidate():呼叫這個方法會執行onDraw()方法,但是前提是:自己把invalidate()方法執行結束在進行執行.
	 */

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawColor(Color.BLACK);
		paint.setColor(Color.RED);
		// 如果當前curRectF=null,也就是第一次訪問,則預設為draw第一個bar
		if (curRectF == null)
			curRectF = new RectF(tv1.getLeft() + space_x, tv1.getTop()
					+ space_y, tv1.getRight() - space_x, tv1.getBottom()
					- space_y);

		// 第一次方位tarRectF=null,預設為draw
		if (tarRectF == null)
			tarRectF = new RectF(tv1.getLeft() + space_x, tv1.getTop()
					+ space_y, tv1.getRight() - space_x, tv1.getBottom()
					- space_y);
		/***
		 * 作用:如果在這個範圍內則,以這個為最終位置,(不明的白的話,你可以把這個註釋執行下你就知道why了.)
		 */
		if (Math.abs(curRectF.left - tarRectF.left) < step) {
			curRectF.left = tarRectF.left;
			curRectF.right = tarRectF.right;
		}

		/***
		 * 說明目標在當前的左側,需要向左移動(每次矩形移動step,則進行invalidate(),從新進行移動...)
		 */
		if (curRectF.left > tarRectF.left) {
			curRectF.left -= step;
			curRectF.right -= step;
			invalidate();// 繼續重新整理,從而實現滑動效果,每次step32.
		}
		/***
		 * 說明目標在當前的右側,需要向右移動(每次矩形移動step,則進行invalidate(),從新進行移動...)
		 */
		else if (curRectF.left < tarRectF.left) {
			curRectF.left += step;
			curRectF.right += step;
			invalidate();
		}
		// canvas.drawRect(curRectF, paint);
		// 引數,矩形,弧度,畫筆
		canvas.drawRoundRect(curRectF, 5, 5, paint);
	}

	/****
	 * 這裡要記錄目標矩形的座標
	 */
	@Override
	public void onClick(View v) {
		tarRectF.left = v.getLeft() + space_x;
		tarRectF.right = v.getRight() - space_x;
		invalidate();// 重新整理

		System.out.println("tarRectF.top=" + tarRectF.top + ",v.getTop()="
				+ v.getTop() + ", v.getBottom()" + v.getBottom());
	}

}
 上面已經講的很詳細了,就不囉嗦了.
  效果圖:
         

 大致就這麼多了。

原始碼下載

額外:還有一點就是有的會用到RadioButton這個控制元件,其實就是對其進行了一些調整,這裡我簡單說明一下應用:
   可以取消button樣式,用android:drawableTop顯示圖片,從而達到想要的效果.

<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" >

    <RadioGroup
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="@drawable/maintab_toolbar_bg"
        android:gravity="center"
        android:orientation="horizontal" >

        <RadioButton
            android:id="@+id/button1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:background="@drawable/home_btn_bg"
            android:button="@null"
            android:drawableTop="@drawable/icon_1_n"
            android:gravity="center"
            android:paddingTop="5dp"
            android:text="首頁"
            android:textSize="12sp" />

        <RadioButton
            android:id="@+id/button2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/home_btn_bg"
            android:button="@null"
            android:drawableTop="@drawable/icon_2_n"
            android:gravity="center"
            android:paddingTop="5dp"
            android:text="簡訊"
            android:textSize="12sp" />

        <RadioButton
            android:id="@+id/button3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/home_btn_bg"
            android:button="@null"
            android:drawableTop="@drawable/icon_3_n"
            android:gravity="center"
            android:paddingTop="5dp"
            android:text="聯絡人"
            android:textSize="12sp" />

        <RadioButton
            android:id="@+id/button4"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/home_btn_bg"
            android:button="@null"
            android:drawableTop="@drawable/icon_4_n"
            android:gravity="center"
            android:paddingTop="5dp"
            android:text="搜尋"
            android:textSize="12sp" />
    </RadioGroup>

</RelativeLayout>
這裡我們還需要selector.xml 
  實現點選效果.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">


    <item android:drawable="@drawable/home_btn_bg_s" android:state_enabled="true" android:state_focused="true" android:state_pressed="false"/>
    <item android:drawable="@drawable/home_btn_bg_s" android:state_enabled="true" android:state_pressed="true"/>
    <item android:drawable="@drawable/home_btn_bg_d" android:state_checked="true" android:state_enabled="true"/>


</selector>

示例圖:

     

原始碼下載

就說這麼多了,情況因人而異.