Android UI之自訂——類似iOS的Tabbar

來源:互聯網
上載者:User

標籤:android   tabbar   自訂ui   

轉載請註明本文出自JFlex的部落格http://blog.csdn.net/jflex/article/details/46492501,請尊重他人的辛勤勞動成果,謝謝!

Android UI之自訂——類似iOS的Tabbar
Tabbar最早出現在iOS,iOS中的TabBarController實現了這個功能,開發起來相當簡單。現在的APP,大多數都會使用Tabbar來作為應用的功能導航,介面簡單清晰。那麼Android常見的實現是通過RadioGroup來實現,今天將帶來自訂實現,補充RadioGroup實現的不足。

先看看常見的軟體中的使用:

這個是高鐵管家APP,大家應該非常熟悉。這個APP的首頁底部就是一個類似iOS的Tabbar。這裡就不多舉例子了,接下來直接進入正題。

RadioGroup實現Tabbar1、為什麼用RadioGroup實現呢
熟悉RadioGroup的都知道,一個RadioGroup中只能選中一個RadioButton。而Tabbar剛好就是這麼一個效果,所以用RadioGroup再好不過了。
2、實現代碼
<RadioGroup        android:id="@+id/rgHomeMenu"        android:layout_width="match_parent"        android:layout_height="60dp"        android:orientation="horizontal" >        <RadioButton            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:button="@null"            android:checked="true"            android:drawableTop="@drawable/icon_project_selector"            android:gravity="center"            android:paddingBottom="5dp"            android:paddingTop="8dp"            android:text="@string/project"            android:textColor="@color/menu_txt_selector"            android:textSize="12sp" />        <RadioButton            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:button="@null"            android:drawableTop="@drawable/icon_msg_selector"            android:gravity="center"            android:paddingBottom="5dp"            android:paddingTop="8dp"            android:text="@string/msg"            android:textColor="@color/menu_txt_selector"            android:textSize="12sp" />        <RadioButton            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:button="@null"            android:drawableTop="@drawable/icon_mine_selector"            android:gravity="center"            android:paddingBottom="5dp"            android:paddingTop="8dp"            android:text="@string/mine"            android:textColor="@color/menu_txt_selector"            android:textSize="12sp" />    </RadioGroup>


- RadioGroup必須使用RadioButton作為子控制項
- 由於Tabbar是片、下文字,所有需要將android:button設定空,去掉RadioButton的預設圖。片設定android:drawableTop屬性,文字設定android:text屬性,其他屬性按照實際需求調整即可。
- 實現起來很簡單,字碼頁比較簡潔。

3、優缺點
  1. 優點:代碼簡潔,容易實現
  2. 缺點:擴充性不足。因為每一個Item是RadioButton,所以只能使用這個空間的相關功能,如果需要擴充,就做不到了。
自訂Tabbar1、需求:比如現在需要在訊息上添加類似iOS的badgeview的訊息提示。

2、實現代碼
  • TabGroup
    這個類需要實作類別似RadioGroup的作用,代碼借鑒RadioGroup實現。

    package com.snicesoft.tabbar;import android.annotation.SuppressLint;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;@SuppressLint("NewApi")public class TabGroup extends LinearLayout {    public TabGroup(Context context, AttributeSet attrs, int defStyleAttr,            int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        init();    }    public TabGroup(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    public TabGroup(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public TabGroup(Context context) {        super(context);        init();    }    private void init() {        setOrientation(HORIZONTAL);    }    int mCheckedId = -1;    OnTabGroupCheckedListener onTabGroupCheckedListener;    public void setOnTabGroupCheckedListener(            OnTabGroupCheckedListener onTabGroupCheckedListener) {        this.onTabGroupCheckedListener = onTabGroupCheckedListener;    }    @Override    public void addView(View child, int index, ViewGroup.LayoutParams params) {        if (child instanceof TabItem) {            final TabItem tab = (TabItem) child;            if (tab.isChecked()) {                check(tab.getId());            }        }        super.addView(child, index, params);    }    public void check(int checkId) {        if (mCheckedId == checkId) {            return;        }        setCheckedStateForView(mCheckedId, false);        setCheckedId(checkId);        mCheckedId = checkId;        if (onTabGroupCheckedListener != null)            onTabGroupCheckedListener.onChecked(checkId);    }    private void setCheckedId(int id) {        View checkedView = findViewById(id);        if (checkedView != null && checkedView instanceof TabItem) {            ((TabItem) checkedView).setChecked(true);        }    }    private void setCheckedStateForView(int viewId, boolean checked) {        View checkedView = findViewById(viewId);        if (checkedView != null && checkedView instanceof TabItem) {            ((TabItem) checkedView).setChecked(checked);        }    }    public interface OnTabGroupCheckedListener {        public void onChecked(int checkedId);    }}
  • TabItem
    TabItem需要整合RadioButton的功能,也需要擴充性更強。所以選擇整合RelativeLayout,需要有check的狀態操作,那麼需要實現Checkable。

    package com.snicesoft.tabbar;import java.util.ArrayList;import java.util.HashMap;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.drawable.Drawable;import android.graphics.drawable.StateListDrawable;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.widget.Checkable;import android.widget.RelativeLayout;@SuppressLint("NewApi")public class TabItem extends RelativeLayout implements Checkable {    private ArrayList<Checkable> chechableList = new ArrayList<Checkable>();    private HashMap<View, StateListDrawable> stateListDrawableMap = new HashMap<View, StateListDrawable>();    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };    public TabItem(Context context, AttributeSet attrs, int defStyleAttr,            int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        init();    }    public TabItem(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    public TabItem(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public TabItem(Context context) {        super(context);        init();    }    private void init() {        super.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                onChecked();                if (OnClickListener != null)                    OnClickListener.onClick(v);            }        });    }    @Override    public void addView(View child, int index,            android.view.ViewGroup.LayoutParams params) {        super.addView(child, index, params);        setStates(child);    }    private void setStates(View child) {        Drawable drawable = child.getBackground();        if (drawable != null && drawable instanceof StateListDrawable) {            stateListDrawableMap.put(child, (StateListDrawable) drawable);        }        child.setClickable(false);        if (child instanceof Checkable) {            chechableList.add((Checkable) child);        }        if (child instanceof ViewGroup) {            final ViewGroup group = (ViewGroup) child;            if (group.getChildCount() > 0) {                for (int i = 0; i < group.getChildCount(); i++) {                    setStates(group.getChildAt(i));                }            }        }    }    OnClickListener OnClickListener;    @Override    public void setOnClickListener(OnClickListener l) {        OnClickListener = l;    }    boolean isChecked = false;    @Override    public void setChecked(boolean checked) {        if (isChecked == checked)            return;        for (Checkable ca : chechableList) {            ca.setChecked(checked);        }        if (checked) {            for (View v : stateListDrawableMap.keySet()) {                StateListDrawable drawable = stateListDrawableMap.get(v);                drawable.setState(CHECKED_STATE_SET);                v.setBackground(drawable.getCurrent());            }        } else {            for (View v : stateListDrawableMap.keySet()) {                v.setBackground(stateListDrawableMap.get(v));            }        }        isChecked = checked;    }    private void onChecked() {        if (getParent() instanceof TabGroup) {            final TabGroup group = (TabGroup) getParent();            group.check(getId());        }    }    @Override    public boolean isChecked() {        return isChecked;    }    @Override    public void setPressed(boolean pressed) {        super.setPressed(pressed);        if (!pressed) {            setChecked(true);        }    }    @Override    public void toggle() {        setChecked(!isChecked);    }}
  • RelativeLayout中的預設帶有Pressed屬性的組件,不如Button,會攔截onClick事件,所以TabItem中的所有組件都背設定不可點擊。

  • 為了讓TabItem的相容性達到RadioButton一樣,所以在setChecked方法中將TabItem中包含的所有整合Checkable的View強制調用setChecked方法,能夠達到同步效果(點擊TabItem的時候,能夠將check的狀態傳遞到子控制項中)
  • 為了讓TabItem中的組件能夠使用selector,需要用到StateListDrawable來控制不同狀態的背景顯示。
3、優缺點
  1. 優點:使用方法和RadioGroup一致,擴充性強
  2. 缺點:layout代碼比RadioGroup多,沒有設定預設checked屬性
總結
這種自訂控制項,只是在原生控制項的基礎上改進,是比較初級的,只需要掌握改進原理,修改的方法很多種的。本人的修改只是一個簡單的示範,希望大家有好的改進方法,不吝賜教。

本例子源碼下載

Android UI之自訂——類似iOS的Tabbar

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.