Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android UI之自定義——類似iOS的Tabbar

Android UI之自定義——類似iOS的Tabbar

編輯:關於Android編程

 

Android UI之自定義——類似iOS的Tabbar

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

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

高鐵管家

這個是高鐵管家APP,大家應該非常熟悉。這個APP的首頁底部就是一個類似iOS的Tabbar。這裡就不多舉例子了,接下來直接進入正題。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxociAvPg0KPGgyIGlkPQ=="radiogroup實現tabbar">RadioGroup實現Tabbar

1、為什麼用RadioGroup實現呢

熟悉RadioGroup的都知道,一個RadioGroup中只能選中一個RadioButton。而Tabbar剛好就是這麼一個效果,所以用RadioGroup再好不過了。

2、實現代碼



        

        

        
    

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

3、優缺點

優點:代碼簡潔,容易實現 缺點:擴展性不足。因為每一個Item是RadioButton,所以只能使用這個空間的相關功能,如果需要擴展,就做不到了。

自定義Tabbar

1、需求:比如現在需要在消息上添加類似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 chechableList = new ArrayList();
    private HashMap stateListDrawableMap = new HashMap();

    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、優缺點

優點:使用方法和RadioGroup一致,擴展性強 缺點:layout代碼比RadioGroup多,沒有設置默認checked屬性

總結

這種自定義控件,只是在原生控件的基礎上改進,是比較初級的,只需要掌握改進原理,修改的方法很多種的。本人的修改只是一個簡單的演示,希望大家有好的改進方法,不吝賜教。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved