前言
在谷歌官方釋出BottomNavigationView控件之前我們可以自己組合控件實作,比如LinearLayout + TextView(使用android:drawableTop屬性+selector狀态切換)、RadioGroup + RadioButton等等組合控件的方法自定義實作複雜效果。除了第三方外,現在我們多了一個選擇,就是使用bottomnavigation結合viewpager的實作。後期會有文章介紹前面的幾種實作方式,對比下來這種代碼量最少,而且特别清晰。
一 使用LinearLayout + TextView實作了底部導航欄的效果
學習一種新的技術首先要看在gradle中的配置(菇涼能力有限這篇文章隻講解這個控件是怎麼用的,感興趣的小夥伴可以去看源代碼):
1.1 build.gradle中
compile'com.android.support:design:25.0.1'
compile'com.android.support:support-v4:25.0.1'
1.2 xml檔案中
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.bottomnavigationview.MainActivity">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_navigation" />
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
app:itemIconTint="@drawable/bottom_selector"
app:itemTextColor="@drawable/bottom_selector"
app:menu="@menu/bottom_menu" />
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_above="@id/bottom_navigation"
android:background="@drawable/bottomshadow" />
</RelativeLayout>
這裡簡單說一下
android.support.design.widget.BottomNavigationView
中的一些屬性:
- app:itemIconTint="@drawable/bottom_selector" :這個是底部欄圖檔顔色變化的selector
- app:itemTextColor="@drawable/bottom_selector":這個是底部欄文字顔色變化的selector
- app:menu="@menu/bottom_menu":這個是底部欄子產品item的定義,包括文字和圖檔
1.3 在res下建立menu檔案夾,建立一個menu菜單 ,代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_news"
android:icon="@mipmap/icon_navigation_home_01"
android:title="首頁" />
<item
android:id="@+id/item_lib"
android:icon="@mipmap/icon_navigation_shop_01"
android:title="搜尋" />
<item
android:id="@+id/item_find"
android:icon="@mipmap/icon_navigation_ucenter_01"
android:title="我的" />
<item
android:id="@+id/item_more"
android:icon="@mipmap/icon_navigation_home_01"
android:title="首頁" />
</menu>
1.4 在drawable下建立.xml檔案 顔色和文字變化的顔色一樣selector,代碼如下
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/p_select_color" android:state_checked="true" />
<item android:color="@color/p_99_color" android:state_checked="false" />
</selector>
1.5 MainActivity中的主要代碼:
package com.bottomnavigationview;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private MenuItem menuItem;
private BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewpager);
bottomNavigationView = (BottomNavigationView)findViewById(R.id.bottom_navigation);
//預設 >3 的選中效果會影響ViewPager的滑動切換時的效果,故利用反射去掉
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.item_news:
viewPager.setCurrentItem(0);
break;
case R.id.item_lib:
viewPager.setCurrentItem(1);
break;
case R.id.item_find:
viewPager.setCurrentItem(2);
break;
case R.id.item_more:
viewPager.setCurrentItem(3);
break;
}
return false;
}
});
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if (menuItem != null) {
menuItem.setChecked(false);
} else {
bottomNavigationView.getMenu().getItem(0).setChecked(false);
}
menuItem = bottomNavigationView.getMenu().getItem(position);
menuItem.setChecked(true);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
//禁止ViewPager滑動
// viewPager.setOnTouchListener(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// return true;
// }
// });
setupViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(BaseFragment.newInstance("首頁"));
adapter.addFragment(BaseFragment.newInstance("搜尋"));
adapter.addFragment(BaseFragment.newInstance("我的"));
adapter.addFragment(BaseFragment.newInstance("首頁"));
viewPager.setAdapter(adapter);
}
}
注意點:
官方的BottomNavigationView用起來雖然簡單,但是有一個很坑的問題,就是它内部在item>4的時候出現動畫的效果。如下:
在平時的開發中這種效果也是特别崩潰的,因為官方沒有預設的方法取消這種效果,這時候需要我們用到反射。
建立一個Helper類
package com.bottomnavigationview;
import android.annotation.TargetApi;
import android.os.Build;
import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import java.lang.reflect.Field;
/**
* Created by 涼菇涼 on 2017/8/2.
*/
public class BottomNavigationViewHelper {
@TargetApi(Build.VERSION_CODES.KITKAT)
public static void disableShiftMode(BottomNavigationView navigationView) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i);
itemView.setShiftingMode(false);
itemView.setChecked(itemView.getItemData().isChecked());
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
使用的時候
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);
1.6 其實避了這個坑是特别簡單的,viewpager就不在這裡詳細說了。來上一張效果動圖。
補充 :
BaseFragment中的代碼
public class BaseFragment extends Fragment {
private static final String EXTRA_CONTENT = "content";
public static BaseFragment newInstance(String content){
Bundle arguments = new Bundle();
arguments.putString(EXTRA_CONTENT, content);
BaseFragment tabContentFragment = new BaseFragment();
tabContentFragment.setArguments(arguments);
return tabContentFragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_tab_content, null);
((TextView)contentView.findViewById(R.id.tv_content)).setText(getArguments().getString(EXTRA_CONTENT));
return contentView;
}
}