这两天在学习设计模式,就使用迭代器模式写了一个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上了,大家可以看下.
源码地址
谢谢.