Android设计模式-迭代器模式-构建一个通用的BottomNavigationView

这两天在学习设计模式,就使用迭代器模式写了一个BottomNavigationView.
首先我们创建一个BottomTabItem类,因为下面的布局是不固定的,所以我们需要传入layoutId.
public abstract class BottomTabItem {
    //布局id ,Context

    private View mTabItemView;

    private Context mContext;

    private int mLayoutId;

    public BottomTabItem(Context context, int layoutId) {
        this.mContext = context;
        this.mLayoutId = layoutId;
    }

    public View getTabView(){
        if (mTabItemView == null){
            mTabItemView = LayoutInflater.from(mContext).inflate(mLayoutId,null);
            initLayout();
        }
        return mTabItemView;
    }

    protected abstract void initLayout();

    protected  <T> T findViewById(int id){
        return (T)mTabItemView.findViewById(id);
    }
    /**
     * 是否选中
     * @param selected
     */
    public abstract void setSelected(boolean selected);
}
在这里我放了三个参数,一个是我们的上下文对象,一个是传入的layoutId,一个是我们的TabView,是通过传入的布局生成的.
接下来我们创建一个实现类MainBottomTabItem继承自BottomTabItem,在这里我们使用了builder设计模式
public class MainBottomTabItem extends BottomTabItem {
    private Builder mBuilder;
    private MainBottomTabItem(Context context, int layoutId){
        super(context,layoutId);
    }

    private MainBottomTabItem(Builder builder){
        super(builder.mContext,R.layout.tab_main_bottom_item);
        this.mBuilder = builder;
    }

    @Override
    protected void initLayout() {
        TextView text = findViewById(R.id.tab_text);
        ImageView icon = findViewById(R.id.tab_icon);
        if (!TextUtils.isEmpty(mBuilder.mText)){
            text.setText(mBuilder.mText);
        }

        if (mBuilder.mResIconId != 0){
            icon.setImageResource(mBuilder.mResIconId);
        }
    }

    @Override
    public void setSelected(boolean selected) {
        TextView text = findViewById(R.id.tab_text);
        ImageView icon = findViewById(R.id.tab_icon);
        getTabView().setSelected(selected);
        text.setSelected(selected);
        icon.setSelected(selected);
    }

    public static class Builder{
        Context mContext;
        String mText;
        int mResIconId;

        public Builder(Context context){
            this.mContext = context;
        }
        public Builder setText(String text){
            this.mText = text;
            return this;
        }

        public Builder setIcon(int resIconId){
            this.mResIconId = resIconId;
            return this;
        }

        public MainBottomTabItem create(){
            return new MainBottomTabItem(this);
        }
    }
}
这个类不难理解,我就不一一解释了
接下来我们看下我们的TabIterator类
首先我们先定义一个接口
public interface TabIterator {
    BottomTabItem next();
    boolean hashNext();
}

下面我们实现一下这个接口

public class TabListIterator<T extends BottomTabItem> implements TabIterator {
    List<T> mTabItems;
    int index = 0;
    public TabListIterator(){
        mTabItems = new ArrayList<>();
    }

    public void addItem(T item){
        mTabItems.add(item);
    }

    @Override
    public BottomTabItem next() {
        return mTabItems.get(index++);
    }

    @Override
    public boolean hashNext() {
        return index<mTabItems.size();
    }
}

这里我们定义了List数据源的,大家也可以定义其他的比如set或者是数组什么的,但需要注意一定需要实现我们的TabIterator.

下面我们创建一个BottomNavigationView继承自LinearLayout

public class BottomNavigationView extends LinearLayout {
    private List<BottomTabItem> mTabItems;
    private int mCurrentIndex = -1;
    private OnItemClickListener mItemClickListener;

    public interface OnItemClickListener{
        public void itemClick(int position);
    }
    public BottomNavigationView(Context context) {
        this(context,null);
    }

    public BottomNavigationView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public BottomNavigationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOrientation(HORIZONTAL);
        mTabItems = new ArrayList<>();
    }

    public void setOnItemClickListener(OnItemClickListener itemClickListener){
        this.mItemClickListener = itemClickListener;
    }

    public void addTabItem(TabIterator iterator){
        mTabItems.clear();
        int index = 0;
        while(iterator.hashNext()){
            BottomTabItem tabItem = iterator.next();
            View tabView = tabItem.getTabView();
            addView(tabView);

            LinearLayout.LayoutParams params = (LayoutParams) tabView.getLayoutParams();
            params.weight = 1;
            params.gravity = Gravity.CENTER;
            tabView.setLayoutParams(params);

            //给条目设置点击事件

            setItemClickListener(tabView,index++);
            mTabItems.add(tabItem);
        }

        mTabItems.get(0).setSelected(true);
        mCurrentIndex = 0;
    }

    private void setItemClickListener(View tabView, final int index) {
        tabView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mCurrentIndex != index){
                    mTabItems.get(mCurrentIndex).setSelected(false);
                    mTabItems.get(index).setSelected(true);
                    mCurrentIndex =index;
                    if (mItemClickListener != null){
                        mItemClickListener.itemClick(mCurrentIndex);
                    }
                }
            }
        });
    }

    public void setCurrentItem(int index){
        if (index < mTabItems.size() && mCurrentIndex != index){
            mTabItems.get(mCurrentIndex).setSelected(false);
            mTabItems.get(index).setSelected(true);
            mCurrentIndex = index;
        }
    }
}

在这里我们addItems传入的是我们定义的TabIterator,这样就保证了数据源的扩展性,如果大家的数据源不一样,可以重新定义TabListIterator这个类,而不需要修改我们的自定义View,只需要在这上面扩展而已.
我们看看我们的布局文件activity_main.xml

在这里插入代码片
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.example.navigationview.view.BottomNavigationView
        android:layout_alignParentBottom="true"
        android:id="@+id/tab_bottom_navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </com.example.navigationview.view.BottomNavigationView>

</RelativeLayout>

比较简单,就不介绍了
最后看看MainActivity

在这里插入代码片
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private BottomNavigationView mTabBottomNavigation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTabBottomNavigation = findViewById(R.id.tab_bottom_navigation);

        TabListIterator iterator = new TabListIterator();

        iterator.addItem(new MainBottomTabItem.Builder(this).setText("item1").setIcon(R.drawable.tab_item_icon_src).create());
        iterator.addItem(new MainBottomTabItem.Builder(this).setText("item2").setIcon(R.drawable.tab_item_icon_src).create());
        iterator.addItem(new MainBottomTabItem.Builder(this).setText("item3").setIcon(R.drawable.tab_item_icon_src).create());
        iterator.addItem(new MainBottomTabItem.Builder(this).setText("item4").setIcon(R.drawable.tab_item_icon_src).create());

        mTabBottomNavigation.addTabItem(iterator);

        mTabBottomNavigation.setOnItemClickListener(new BottomNavigationView.OnItemClickListener() {
            @Override
            public void itemClick(int position) {
                Log.e(TAG,"itemClick--positiom="+position);
            }
        });

        mTabBottomNavigation.setCurrentItem(2);
    }
}

这样我们的代码就基本上完成了,我们来看看运行效果.

在这里插入图片描述
大概就是这样.

其实我们用这个迭代器模式,主要是解决了数据源格式不一样的问题,这样扩展性比较强.

代码已经上传到了github上了,大家可以看下.
源码地址

谢谢.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值