Android底部導航欄——bottomnavigation結合viewpager的實現
前言
在谷歌官方釋出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.4 在drawable下新建.xml檔案 顏色和文字變化的顏色一樣selector,程式碼如下<?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>
<?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;
}
}