Android UI之自定义——类似iOS的Tabbar

转载请注明本文出自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实现Tabbar

1、为什么用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,所以只能使用这个空间的相关功能,如果需要扩展,就做不到了。

自定义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<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属性

总结

这种自定义控件,只是在原生控件的基础上改进,是比较初级的,只需要掌握改进原理,修改的方法很多种的。本人的修改只是一个简单的演示,希望大家有好的改进方法,不吝赐教。

本例子源码下载

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值