Android微信支付宝的底部导航栏是怎么做的?简单的导航栏蕴藏着大智慧!
2017-11-29 02:15
609 查看
常见做法1:
套框架
常见做法2:
在底部写一个水平的LinearLayout作为导航栏,每个Item又是一个垂直的LinearLayout。
。。。
不是说上述做法不好。
做法1不能满足个性定制的需求
做法2嵌套层级太多,拖慢了性能;MainActivity中做事太多,负荷太大
正确做法:
为了维护,我们的模块化原子化是前期开发时必不可少的工作。这里体现的原子性是:
1.底部用碎片取代LinerLayout
2.每个item都作为一个自定义控件,都维护(缓存)了主界面布局碎片的实例。
3.切换碎片的形式采用attach和detach,而不是hide和show,无形中减小了负担,增加了容错率。
4.切换碎片不再是在MainActivity中一个一个地去实例化碎片,而是交给自定义的item控件去维护
先看一下自定义Item控件的代码
xml
java
维护的变量
取得xml并加载的形式,this代表这个xml的父布局就是这个自定义view,再用getChildAt的形式取得碎片中的控件,体现了开闭原则
全部代码(完全符合开闭原则,使用的时候不需要修改这个自定义控件任何的代码)
底部导航栏碎片代码
xml,想修改布局直接去改item的布局即可
java
初始化前清空所有碎片,防止出错
切换item的操作
doTabChanged
全部代码
效果图(素材找的不是很好)
看起来还没有第三方那些绚丽?但是微信支付宝都是这样的,简单素净,高端app必备。而且其代码的可维护性和重用性才是重中之中。
套框架
常见做法2:
在底部写一个水平的LinearLayout作为导航栏,每个Item又是一个垂直的LinearLayout。
。。。
不是说上述做法不好。
做法1不能满足个性定制的需求
做法2嵌套层级太多,拖慢了性能;MainActivity中做事太多,负荷太大
正确做法:
为了维护,我们的模块化原子化是前期开发时必不可少的工作。这里体现的原子性是:
1.底部用碎片取代LinerLayout
2.每个item都作为一个自定义控件,都维护(缓存)了主界面布局碎片的实例。
3.切换碎片的形式采用attach和detach,而不是hide和show,无形中减小了负担,增加了容错率。
4.切换碎片不再是在MainActivity中一个一个地去实例化碎片,而是交给自定义的item控件去维护
先看一下自定义Item控件的代码
xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="50dp"> <ImageView android:id="@+id/nav_icon" android:layout_width="35dp" android:layout_height="35dp" android:layout_gravity="center_horizontal" tools:background="@mipmap/ic_launcher" /> <TextView android:id="@+id/nav_title" android:layout_gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="15dp" tools:text="微信"/> </LinearLayout>
java
维护的变量
private Fragment mFragment = null;//这个是你维护的主界面的碎片实例 private ImageView mIcon; private TextView mTitle; private Class<?> mClx; private String mTag;
取得xml并加载的形式,this代表这个xml的父布局就是这个自定义view,再用getChildAt的形式取得碎片中的控件,体现了开闭原则
LayoutInflater inflater = LayoutInflater.from(getContext()); inflater.inflate(itemLayoutId, this, true); ViewGroup vg = (ViewGroup) this.getChildAt(0); mIcon = (ImageView) vg.getChildAt(0); mTitle = (TextView) vg.getChildAt(1);
全部代码(完全符合开闭原则,使用的时候不需要修改这个自定义控件任何的代码)
public class NavButton extends FrameLayout {
private Fragment mFragment = null;//这个是你维护的主界面的碎片实例 private ImageView mIcon; private TextView mTitle; private Class<?> mClx; private String mTag;
public NavButton(@NonNull Context context) {
super(context);
}
public NavButton(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public NavButton(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public NavButton(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private int uncheckedTitle;
private int checkedTitle;
private int uncheckedIcon;
private int checkedIcon;
public void init(@DrawableRes int uncheckedIcon, @DrawableRes int checkedIcon, @ColorInt int uncheckedTitle, @ColorInt int checkedTitle, String s, Class<?> clx, int itemLayoutId) {
LayoutInflater inflater = LayoutInflater.from(getContext()); inflater.inflate(itemLayoutId, this, true); ViewGroup vg = (ViewGroup) this.getChildAt(0); mIcon = (ImageView) vg.getChildAt(0); mTitle = (TextView) vg.getChildAt(1);
mTitle.setText(s);
if (uncheckedTitle == 0) {
this.uncheckedTitle = mTitle.getCurrentTextColor();
} else {
this.uncheckedTitle = uncheckedTitle;
mTitle.setTextColor(uncheckedTitle);
}
this.checkedTitle = checkedTitle;
this.uncheckedIcon = uncheckedIcon;
this.checkedIcon = checkedIcon;
mIcon.setImageDrawable(getResources().getDrawable(uncheckedIcon));
mClx = clx;
mTag = mClx.getName();
}
public Fragment getFragment() {
return mFragment;
}
public Class<?> getClx() {
return mClx;
}
public String getTag() {
return mTag;
}
public void setFragment(Fragment mFragment) {
this.mFragment = mFragment;
}
@Override
public void setSelected(boolean selected) {
super.setSelected(selected);
if (selected) {
mTitle.setTextColor(checkedTitle);
mIcon.setImageDrawable(getResources().getDrawable(checkedIcon));
} else {
mTitle.setTextColor(uncheckedTitle);
mIcon.setImageDrawable(getResources().getDrawable(uncheckedIcon));
}
}
}
底部导航栏碎片代码
xml,想修改布局直接去改item的布局即可
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.wechat.nav.NavButton android:id="@+id/nav_chat" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent"/> <com.example.wechat.nav.NavButton android:id="@+id/nav_friends" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent"/> <com.example.wechat.nav.NavButton android:id="@+id/nav_find" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent"/> <com.example.wechat.nav.NavButton android:id="@+id/nav_me" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent"/> </LinearLayout>
java
初始化前清空所有碎片,防止出错
private void clearOldFragment() { FragmentTransaction transaction = getFragmentManager().beginTransaction(); List<Fragment> fragments = getFragmentManager().getFragments(); if (transaction == null || fragments == null || fragments.size() == 0) return; boolean doCommit = false; for (Fragment fragment : fragments) { if (fragment != this && fragment != null) { transaction.remove(fragment); doCommit = true; } } if (doCommit) transaction.commitNow(); }
切换item的操作
//思路:把将选的item和当前的item作为新老碎片,mCurrent是当前维护的即选中的item private void doSelect(NavButton newNav) { NavButton oldNav = null; //拦截点击当前选中的按钮 if (mCurrentNav != null) { oldNav = mCurrentNav; if (oldNav == newNav) { return; } } //这里进行的操作:1.item的切换2.主布局碎片的切换 doTabChanged(oldNav, newNav, mContainerId); mCurrentNav = newNav; }
doTabChanged
private void doTabChanged(NavButton oldNav, NavButton newNav, int mContainerId) { FragmentTransaction transaction = getFragmentManager().beginTransaction(); //将设置选中和设置未选中分立开来 if (oldNav != null) {//这里判空主要防止异常情况和第一次显示设置默认item的选中 if (newNav.getFragment() != null) {//这里的newNav要修改为oldNav,我擦,被开源中国的代码坑了!这是bug啊。找了我老半天 transaction.detach(oldNav.getFragment());//切换主布局碎片显示 } oldNav.setSelected(false);//切换item显示 } if (newNav != null) { if (newNav.getFragment() == null) { Fragment fragment = Fragment.instantiate(getActivity(), newNav.getClx().getName(), null); transaction.add(mContainerId, fragment, newNav.getTag());//给tag加快取得速度 newNav.setFragment(fragment);//交给他去维护,这是一个缓存机制 } else { transaction.attach(newNav.getFragment());//采用attach和detach比hide,show性能更高 } newNav.setSelected(true); } transaction.commit(); }
全部代码
public class NavFragment extends BaseFragment implements View.OnClickListener { private FragmentManager mFragmentManager; private Context mContext; private int mContainerId; public NavFragment() { } @BindView(R.id.nav_chat) protected NavButton mChat; @BindView(R.id.nav_friends) protected NavButton mFriends; @BindView(R.id.nav_find) protected NavButton mFind; @BindView(R.id.nav_me) protected NavButton mMe; @Override protected int getLayoutId() { return R.layout.fragment_nav; } @Override protected void initData() { mContainerId = R.id.fl_main_container; clearOldFragment(mFragmentManager); } @Override protected void initWidget(View mRoot) {
//这里就是传的参数:未选中图片,选中图片,0(初始文字,0为不设置)。。
mChat.init(R.drawable.nav_chat_unchecked, R.drawable.nav_chat_checked, 0, getResources().getColor(R.color.nav), "微信", ChatFragment.class, R.layout.nav_item);
mFriends.init(R.drawable.nav_friends_unchecked, R.drawable.nav_friends_checked, 0, getResources().getColor(R.color.nav), "通讯录", FriendsFragment.class, R.layout.nav_item);
mFind.init(R.drawable.nav_find_unchecked, R.drawable.nav_find_checked, 0, getResources().getColor(R.color.nav), "发现", FindFragment.class, R.layout.nav_item);
mMe.init(R.drawable.nav_me_unchecked, R.drawable.nav_me_checked, 0, getResources().getColor(R.color.nav), "我", MeFragment.class, R.layout.nav_item);
doSelect(mChat);
}
private NavButton mCurrentNav = null;
//思路:把将选的item和当前的item作为新老碎片,mCurrent是当前维护的即选中的item private void doSelect(NavButton newNav) { NavButton oldNav = null; //拦截点击当前选中的按钮 if (mCurrentNav != null) { oldNav = mCurrentNav; if (oldNav == newNav) { return; } } //这里进行的操作:1.item的切换2.主布局碎片的切换 doTabChanged(oldNav, newNav, mContainerId); mCurrentNav = newNav; }
private void doTabChanged(NavButton oldNav, NavButton newNav, int mContainerId) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
//将设置选中和设置未选中分立开来
if (oldNav != null) {//这里判空主要防止异常情况和第一次显示设置默认item的选中
if (newNav.getFragment() != null) {
transaction.detach(oldNav.getFragment());//切换主布局碎片显示
}
oldNav.setSelected(false);//切换item显示
}
if (newNav != null) {
if (newNav.getFragment() == null) {
Fragment fragment = Fragment.instantiate(getActivity(),
newNav.getClx().getName(), null);
transaction.add(mContainerId, fragment, newNav.getTag());//给tag加快取得速度
newNav.setFragment(fragment);//交给他去维护,这是一个缓存机制
} else {
transaction.attach(newNav.getFragment());//采用attach和detach比hide,show性能更高
}
newNav.setSelected(true);
}
transaction.commit();
}
private void clearOldFragment(FragmentManager mFragmentManager) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
List<Fragment> fragments = mFragmentManager.getFragments();
if (transaction == null || fragments == null || fragments.size() == 0)
return;
boolean doCommit = false;
for (Fragment fragment : fragments) {
if (fragment != this && fragment != null) {
transaction.remove(fragment);
doCommit = true;
}
}
if (doCommit)
transaction.commitNow();
}
@OnClick({R.id.nav_chat, R.id.nav_friends, R.id.nav_find, R.id.nav_me})
@Override
public void onClick(View v) {
if (v instanceof NavButton) {
NavButton nav = (NavButton) v;
doSelect(nav);
}
}
// TODO: 2017/11/27 chat双击监听
}
效果图(素材找的不是很好)
看起来还没有第三方那些绚丽?但是微信支付宝都是这样的,简单素净,高端app必备。而且其代码的可维护性和重用性才是重中之中。
相关文章推荐
- android BottomTabBar的简单使用(类似:京东底部导航栏)
- 超简单的几行代码搞定Android底部导航栏功能
- Android实现简单底部导航栏 Android仿微信滑动切换效果
- Android --中间突出的底部导航栏布局简单实现
- [置顶] Android 底部导航栏 BottomNavigationBar的简单使用
- Android 底部导航栏的简单实现-BottomNavigationView
- 底部导航栏:超简单,几行代码搞定Android底部导航栏
- Android 底部导航栏 中间凸起
- Android:简单实现ViewPager+TabHost+TabWidget实现导航栏导航和滑动切换
- Android 底部导航栏(底部Tab)最佳实践
- Android 底部导航栏按钮突出
- android 开发实例 底部导航栏(1)
- Android学习Material design中的底部导航栏BottomNavigationBar
- Android学习之BottomNavigationBar实现Android特色底部导航栏
- Android底部导航栏的开源控件BottomNavigationBar
- Android虚拟导航栏遮挡底部的输入框
- Android应用底部导航栏(选项卡)实例
- Navigation-bar 一个简单方便的底部导航栏模版
- Android学习之BottomNavigationBar实现Android特色底部导航栏
- Android 底部导航栏(底部Tab)最佳实践