Android Training学习笔记——Navigation
来源:互联网 发布:聚合数据公司 编辑:程序博客网 时间:2024/04/29 18:55
转载请注明出处:http://blog.csdn.net/xroocky/article/details/50767844
参考源码:
ListView版:http://download.csdn.net/detail/xroocky/9448415
NavigationView版:http://download.csdn.net/detail/xroocky/9448363
Ps:我的源码中存在一个很重要的问题,当使用DrawerLayout进行Fragment切换后,会发现二次进入包含Tab的Fragment时,Fragment的内容没有加载出来,而且Tab切换很不流畅。。。一直不知道问题出在哪里,有朋友知道原因的话劳烦告知一下,谢谢了~
创建滑动View和Tab
一、实现滑动View
滑动View是需要通过ViewPager来实现的,因此需要在布局文件中插入ViewPager
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" />
向ViewPager中添加子view作为page需要为其设置Adapter,有
FragmentPagerAdapter
和FragmentStatePagerAdapter
两种Adapter可供选择,FragmentPagerAdapter
适用于page个数确定且较少的情况,FragmentStatePagerAdapter
则适用于page个数不确定的情况,而且当切换page时可以通过销毁不显示的page来使内存最小化。所以一般FragmentStatePagerAdapter
用得比较多。public class MainActivity extends AppCompatActivity { private List<Fragment> fragmentList = new ArrayList<>(); private List<String> titleList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager viewPager = (ViewPager)findViewById(R.id.viewpager); viewPager.setAdapter(new VIewPagerAdapter(getSupportFragmentManager(), fragmentList, titleList)); }}
public class ViewPagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> fragmentList; private List<String> titleList; public VIewPagerAdapter(FragmentManager fm, List fragmentList, List titleList) { super(fm); this.fragmentList = fragmentList; this.titleList = titleList; } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public int getCount() { return fragmentList.size(); } @Override public CharSequence getPageTitle(int position) { return titleList.get(position); }}
到这里滑动View就已经实现了,还缺少Tabs来标识一下当前是在哪个View,接下来就来学习一下如何添加Tabs。
二、向Action Bar添加Tabs
Training里面给了两种方法添加Tabs,一种是通过actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS)方法来设置ActionBar的导航模式为Tabs导航,然后再调用actionBar.addTab()方法来为ActionBar添加Tabs,但是在AS里面使用这种方法时发现谷歌已经不推荐使用这种方法了,这……是Training还没及时更新么?另外一种方法是通过向布局文件中的ViewPager里面添加PagerTitleStrip
来自动生成Tabs,然而这种方法似乎实现的Tabs太简陋了。后来在网上查找了一番得知,目前谷歌最推荐的方式是使用支持库中的TabLayout,具体方法如下。
添加dependencies
compile ‘com.android.support:design:23.1.1’
在布局文件中添加TabLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorPrimary" app:tabIndicatorColor="@android:color/white" app:tabSelectedTextColor="@android:color/white" app:tabTextColor="@color/Indigo_100" android:elevation="4dp"/> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" /></LinearLayout>
设置添加并绑定Tab
TabLayout tabLayout = (TabLayout)view.findViewById(R.id.tab_layout); tabLayout.setTabMode(TabLayout.MODE_FIXED); //模式有MODE_FIXED或MODE_SCROLLABLE两种 tabLayout.addTab(tabLayout.newTab().setText(titleList.get(0))); tabLayout.addTab(tabLayout.newTab().setText(titleList.get(1))); tabLayout.setupWithViewPager(viewPager);
此时Tabs已经添加并且和ViewPager绑定好了!
创建Navigation Drawer
一、创建Drawer Layout
向布局文件中添加DrawerLayout
<android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- The main content view --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/my_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:titleTextColor="@android:color/white"/> <FrameLayout android:id="@+id/fl_main" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <!-- The navigation drawer --> <ListView android:id="@+id/left_drawer" android:layout_width="320dp" android:layout_height="match_parent" android:layout_gravity="start" //如果系统语言是right-to-left,Drawer会出现在屏幕右侧 android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" android:background="#fff"/></android.support.v4.widget.DrawerLayout>
在DrawerLayout中,第一个child必须是界面内容展示区,第二个child必须是Drawer。Drawer的宽度不要超过320dp。
二、初始化Drawer List
为ListView设置适配器并绑定点击事件
listView.setAdapter(new ArrayAdapter<>(this, R.layout.drawer_list_items, drawerItems));listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); }});
其中可以把字符串数组写进资源文件中,通过
R.array.*
来引用,具体使用方法在String ArrayString[] drawerItems = getResources().getStringArray(R.array.str_drawer_items);
ListView的适配器的
R.layout.drawer_list_items
参数定义的是ListView的一项显示效果,这里的布局文件中只有一个TextView
<TextView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@android:id/text1"android:layout_width="match_parent"android:layout_height="wrap_content"android:textAppearance="?android:attr/textAppearanceListItemSmall"android:gravity="center_vertical"android:paddingLeft="16dp"android:paddingRight="16dp"android:textColor="#000"android:background="?android:attr/activatedBackgroundIndicator"android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
TextView
的background
属性为activatedBackgroundIndicator
,这个属性值决定了ListView的item被选中的效果,被选中后该item默认背景颜色会变成colorAccent
,所以可以通过修改colorAccent
来改变ListView的item被选中的效果。另外可以通过改写activatedBackgroundIndicator
的值来改变效果,具体方法如下:
在Drawable
文件夹下新建xml文件listview_background.xml
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_activated="true" android:drawable="@color/colorListview" /><item android:drawable="@android:color/transparent" /></selector>
然后在
styles.xml
文件中添加如何item即可<item name="android:activatedBackgroundIndicator">@drawable/listview_background</item>
三、处理ListView点击事件
因为在打开APP后没有点击Drawer中ListView时需要将ListView设定为第一个item被选中并在内容展示区显示默认内容,所以把点击响应事件单独写成一个
selectItem(position)
方法,在初始化时调用selectItem(0)
private void selectItem(int position) { // update the main content by replacing fragments fragmentManager.beginTransaction().replace(R.id.fl_main, fragmentList.get(position)).commit(); // update selected item and title, then close the drawer listView.setItemChecked(position, true); setTitle(drawerItems[position]); drawerLayout.closeDrawer(listView);}
四、监听Drawer打开关闭事件
可以通过实现
DrawerLayout.DrawerListener
接口来重写回调函数onDrawerOpened()
和onDrawerOpened()
,从而监听Drawer。然而为了更好地实现Action Bar和Drawer的交互,还可以通过ActionBarDrawerToggle
来监听Drawer。actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, (Toolbar)findViewById(R.id.my_toolbar), R.string.drawer_open, R.string.drawer_close) { public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); getSupportActionBar().setTitle(mTitle); //mTitle为Drawer每个item的名称,会变 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() } public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); getSupportActionBar().setTitle(mDrawerTitle); //mDrawerTitle为App名称,不会变 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() } }; //下面这句同样也是使Drawer图标动态变化的关键 drawerLayout.setDrawerListener(actionBarDrawerToggle);
通过
onPrepareOptionsMenu
方法来实现Action Bar的菜单隐藏/* Called whenever we call invalidateOptionsMenu() */@Overridepublic boolean onPrepareOptionsMenu(Menu menu) { // If the nav drawer is open, hide action items related to the content view boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList); menu.findItem(R.id.action_favorite).setVisible(!drawerOpen); return super.onPrepareOptionsMenu(menu);}
五、通过App图标打开关闭Drawer
通过以下代码打开Drawer在Action Bar的图标:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);getSupportActionBar().setHomeButtonEnabled(true);
还需添加以下代码,
onPostCreate
方法中的syncState
是用来设置Drawer图标的(设置成默认图标),onConfigurationChanged
方法是在用户配置改变后用来改变actionBarDrawerToggle
配置的(具体不是很清楚……),因为Drawer的图标也是在Action Bar,所以需要在onOptionsItemSelected
处理它的点击@Overrideprotected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. actionBarDrawerToggle.syncState();}@Overridepublic void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); //This method should always be called by your Activity's onConfigurationChanged method. actionBarDrawerToggle.onConfigurationChanged(newConfig);}@Overridepublic boolean onOptionsItemSelected(MenuItem item) { // Pass the event to ActionBarDrawerToggle, if it returns // true, then it has handled the app icon touch event if (actionBarDrawerToggle.onOptionsItemSelected(item)) { return true; } // Handle your other action bar items... switch (item.getItemId()) { case R.id.action_favorite: break; default: break; } return super.onOptionsItemSelected(item);}
到这里,Navigation Drawer基本就创建完成了。Training里面的Drawer是使用ListView布局的,然而在目前的支持库中有个名为
NavigationView
的控件,是谷歌让开发者直接拿来用的Drawer,接下来就来试试NavigationView
六、使用NavigationView创建Drawer
NavigationView
是谷歌提供的一个便于布局Drawer的控件,只需为其设置好app:headerLayout
和app:menu
属性,就可以得到很美观的Drawer
将原来的
ListView
换成NavigationView
<android.support.design.widget.NavigationView android:id="@+id/navigation" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/drawer_header" app:menu="@menu/drawer_items" />
headerLayout
属性定义的是Drawer的头部布局,menu
定义的是Drawer中的菜单//drawer_header.xml<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="150dp"><ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/google" android:scaleType="centerCrop"/><RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"></RelativeLayout></FrameLayout>
Drawer的头部布局我原本是打算直接给
FrameLayout
设置一个background
属性,属性值就是一张图片,可是由于长宽比例不合适导致图片拉伸变形。因此只好采用现在这种添加一个ImageView
,并为其设置scaleType
属性的方法来避免背景拉伸,大家如果有其他的方法在留言板说一下呀~<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"><group android:id="@+id/gp_first" android:checkableBehavior="single"> <item android:id="@+id/item_1" android:title="首页" android:checked="true"/> <item android:id="@+id/item_2" android:title="发现" /> <item android:id="@+id/item_3" android:title="关注" /></group><item android:id="@+id/gp_second" android:title="应用设置"> <menu> <item android:id="@+id/item_4" android:title="切换主题" android:checkable="true"/> <item android:id="@+id/item_5" android:title="设置" android:checkable="true"/> </menu></item></menu>
当使用子菜单时,需为每个条目设置
android:checkable="true"
属性来实现单选。如果仅仅是为菜单分组,而非子菜单的话,把两组菜单分别放入一个group
中即可,需注意的是要为group
设置id,否则app会分不清两个group
,把两个group
的item
显示到一个列表中。处理
NavigationView
点击事件navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem item) { if (item.getItemId() == R.id.item_1 || item.getItemId() == R.id.item_2 || item.getItemId() == R.id.item_3 || item.getItemId() == R.id.item_4 || item.getItemId() == R.id.item_5) { item.setChecked(true); selectItem(item.getItemId(), item.getTitle().toString()); } return true; } });
private void selectItem(Integer id, String title) { // update the main content by replacing fragments fragmentManager.beginTransaction().replace(R.id.fl_main, fragmentMap.get(id)).commit(); // update selected item and title, then close the drawer getSupportActionBar().setTitle(title); drawerLayout.closeDrawers();}
Drawer图标颜色问题
默认的颜色是黑色,与白色的标题很不搭,于是想办法把它改成白色。直接将android:textColorPrimary
改成白色可以实现效果,但是其他不想变成白色的地方也成白色了……后来在网上看到了修改styles.xml
文件的方法
问题的关键不是Drawer图标的默认颜色是黑色,而是Toolbar
的theme
设置不合理,把Toolbar
的theme
设置为android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
,popupTheme
设置为app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
即可status bar
透明处理
为API>=21的系统建立一个styles
资源文件如下,并且需要为DrawerLayout
添加属性android:fitsSystemWindows="true"
<?xml version="1.0" encoding="utf-8"?><resources><style name="AppTheme" parent="AppTheme.Base"> <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">@android:color/transparent</item></style></resources>
- Android Training学习笔记——Navigation
- Android Training学习笔记——WebView
- Android Training学习笔记
- Android Training学习笔记——App Bar
- Android Training学习笔记——RecyclerView和CardView
- Android training课程学习笔记...
- IOS开发学习笔记——Navigation学习
- iOS学习笔记——导航栏(Navigation)
- cesiumjs学习笔记之三——cesium-navigation插件
- 【学习笔记】Navigation
- Android Training学习笔记之开始篇
- Android学习 - Navigation Drawer
- WPF 学习笔记 - 3. Navigation
- WPF 学习笔记 - 3. Navigation
- Android官方Training学习——Multimedia多媒体
- android training 学习笔记001-android入门基础
- android training 学习笔记002-Android分享操作
- Android Training相关笔记
- js+html写的弱智游戏,坦克发射
- Servlet简介
- 第六届蓝桥杯 三羊献瑞
- yum源
- Mahout决策树算法源码分析(2)
- Android Training学习笔记——Navigation
- mac下mysql5.7默认密码修改
- 抽空了解一下opencv的文件系统结构
- PAT——A+B和C
- Java集合类: Set、List、Map、Queue使用方法详解
- 正则表达式的学习(一)
- java中的匿名内部类总结
- HashMap,LinkedHashMap,TreeMap的区别
- 虚幻4 C++绑定Delegate