前言:
Android端采用底部導(dǎo)航欄的APP非常多赖淤,比如微信蜀漆、微博、支付寶...等等咱旱,這也不能說(shuō)是盲目學(xué)習(xí)iOS确丢,畢竟好東西大家都可以用,各家操作系統(tǒng)也都在博采眾長(zhǎng)吐限,互相學(xué)習(xí)鲜侥。Android端的底部導(dǎo)航欄有著一套規(guī)范,詳情诸典。
這篇文章為大家?guī)?lái)
1.官方BottomNavigationView的使用方法
2.結(jié)合ViewPager描函、Fragment實(shí)現(xiàn)一個(gè)流行UI布局!
3.并用反射解決ViewPager與BottomNavigationView側(cè)滑聯(lián)動(dòng)時(shí)的一個(gè)小問(wèn)題狐粱。
最終實(shí)現(xiàn)效果:
在谷歌官方發(fā)布BottomNavigationView控件之前我們可以自己組合控件實(shí)現(xiàn)舀寓,比如LinearLayout + TextView(使用android:drawableTop屬性+selector狀態(tài)切換)、RadioGroup + RadioButton等等組合控件的方法自定義實(shí)現(xiàn)復(fù)雜效果肌蜻。除了第三方外互墓,現(xiàn)在我們多了一個(gè)選擇。
開(kāi)始
1.新建project然后導(dǎo)入以下support:design library蒋搜,BottomNavigationView就在這個(gè)design庫(kù)中篡撵。順帶導(dǎo)入這個(gè)V4包判莉,因?yàn)榇龝?huì)要使用到ViewPager(這里其實(shí)不用記這么麻煩的庫(kù)跟版本怎么寫(xiě),直接在AS 的design面板把控件拖進(jìn)來(lái)就會(huì)自動(dòng)導(dǎo)入了育谬。)
compile'com.android.support:design:25.0.1'
compile'com.android.support:support-v4:25.0.1'
2.在res下新建menu文件夾券盅,新建一個(gè)menu菜單,多少個(gè)可以根據(jù)自己的需要:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/item_news" android:icon="@mipmap/ic_news_gray" android:title="新聞" />
<item android:id="@+id/item_lib" android:icon="@mipmap/ic_library_gray" android:title="圖書(shū)" />
<item android:id="@+id/item_find" android:icon="@mipmap/ic_discovery_gray" android:title="發(fā)現(xiàn)" />
<item android:id="@+id/item_more" android:icon="@mipmap/ic_more_gray" android:title="更多" />
</menu>
3.接著是布局文件主要代碼如下(最下面的View效果是加一個(gè)陰影):
<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_navigation_selector"
app:itemTextColor="@drawable/bottom_navigation_selector"
app:menu="@menu/menu_bottom_navigation" />
<View
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_above="@id/bottom_navigation"
android:background="@drawable/bottom_shadow" />
app:itemIconTint="@drawable/bottom_navigation_selector" 為icon著色膛檀,寫(xiě)個(gè)selector即可锰镀。
app:itemTextColor="@drawable/bottom_navigation_selector"該屬性為文字著色,同樣寫(xiě)個(gè)selector實(shí)現(xiàn)點(diǎn)擊顏色切換的效果宿刮。
4.寫(xiě)完布局寫(xiě)代碼互站,完整activity文件如下:
實(shí)例化控件后為NavigationView添加監(jiān)聽(tīng)事件即可,代碼如下:
package com.fedming.bottomnavigationdemo;
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;
import com.example.think.shaiwangbaodian.R;
import com.example.think.shaiwangbaodian.base.BaseFragment;
/**
* Created by 程大龍 on 2018/10/15.
* HomeActivity 主界面
*/
public class HomeActivity extends AppCompatActivity {
private ViewPager viewPager;
private MenuItem menuItem;
private BottomNavigationView bottomNavigationView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
viewPager = (ViewPager) findViewById(R.id.viewpager);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
//默認(rèn) >3 的選中效果會(huì)影響ViewPager的滑動(dòng)切換時(shí)的效果僵缺,故利用反射去掉
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) { }
});
setupViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(BaseFragment.newInstance("新聞"));
adapter.addFragment(BaseFragment.newInstance("圖書(shū)"));
adapter.addFragment(BaseFragment.newInstance("發(fā)現(xiàn)"));
adapter.addFragment(BaseFragment.newInstance("更多"));
viewPager.setAdapter(adapter);
}
}
可以看到BottomNavigationView+ViewPager+Fragment可以實(shí)現(xiàn)流行的布局框架胡桃。
不知道細(xì)心的朋友是否可能發(fā)現(xiàn)了,上面的代碼為什么用了反射呢磕潮?
原因就是官方的BottomNavigationView默認(rèn)有個(gè)放大的ShiftingMode效果翠胰,但是尚未支持代碼層級(jí)的切換。在3個(gè)menu item及以下時(shí)默認(rèn)關(guān)閉自脯,而到了4個(gè)及以上時(shí)就懵逼了之景,因?yàn)槲覀兪且鯲iewPager的側(cè)滑。
沒(méi)辦法了膏潮,查了一圈資料锻狗,發(fā)現(xiàn)官方這個(gè)控件還不支持代碼層級(jí)的切換選項(xiàng)(如果你發(fā)現(xiàn)了,請(qǐng)告訴我)焕参。迫不得已轻纪,只能看源碼,開(kāi)啟反射模式了叠纷!
import android.support.design.internal.BottomNavigationItemView;
import android.support.design.internal.BottomNavigationMenuView;
import android.support.design.widget.BottomNavigationView;
import java.lang.reflect.Field;
public class BottomNavigationViewHelper {
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();
}
}
}
我們通過(guò)反射拿到了BottomNavigationMenuView刻帚,至于為什么是BottomNavigationView 的第一個(gè)子View這就要看源碼了,AS中直接可以點(diǎn)進(jìn)去看涩嚣。然后我們知道了這個(gè)效果是由mShiftingMode來(lái)決定的崇众,那么上面的代碼就好理解了。
在實(shí)例化BottomNavigationView后調(diào)用一次這行代碼即可:
BottomNavigationViewHelper.disableShiftMode(bottomNavigationView;
如果不需要配置側(cè)滑切換的話航厚,直接默認(rèn)效果就好顷歌,不要去反射修改了。禁止滑動(dòng)時(shí)幔睬,為ViewPager添加setOnTouchListener接口眯漩,在onTouch下直接消費(fèi)掉點(diǎn)擊事件。添加下面這段代碼:
//禁止ViewPager滑動(dòng)
viewPager.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v,MotionEvent event){
return true;
}
});
最后來(lái)看下效果:
在文章的最后附上源碼大家有什么意見(jiàn)或者補(bǔ)充的可以指出溪窒。