我的手機助手開發日誌---1
目錄:
1、我的手機助手簡介
2、DrawerLayout+NavigationLayout實現側滑選單
3、使用ToolBar代替ActionBar,與側滑選單進行整合
4、TabLayout+ViewPager+Fragment實現可滑動的頂部選單
1. 我的手機助手簡介
我的手機助手是一款簡單易用的應用市場,包括各種App的排行,分類,推薦,搜尋功能。提供App的下載,支援多個App同時下載以及斷點續傳。有應用安裝管理模組,能夠解除安裝已經安裝的應用,提醒需要升級的應用。同時還具有安裝包管理、登入等功能。
2. DrawerLayout+NavigationLayout實現側滑選單
DrawerLayout用於實現側滑選單,也就是在App的主內容介面下,通過側滑或者點選相應按鈕實現開啟側滑選單。一般側滑選單裡面含有一些設定資訊,使用者資訊。下圖是一個典型的DrawerLayout側滑事件觸發後的例圖:
側滑控制元件裡面,使用了一個NavigationLayout控制元件。NavigationLayout包括兩個佈局,一是上方的HeaderLayout,用於顯示一些使用者資訊;二是下方的Menu,顯示一些選項。下面分步驟討論側滑選單的具體實現細節:
1、首先,要以android.support.v4.widget.DrawerLayout為根控制元件。在DrawerLayout下面包含兩個控制元件:
一是內容控制元件(可採用LinearLayout佈局實現);
二是側滑控制元件,採用android.support.design.widget.NavigationView控制元件來實現。
2、將DrawerLayout定義好後,便要在MainActivity中獲取到其控制元件,並且加上相應監聽器,使其能夠相應側滑事件。
將DrawerLayout繫結上監聽事件。
3、內容控制元件的總佈局是在一個LinearLayout下進行處理,內部可以採用各種佈局。比如說我們後面要是用的ToolBar+TabLayout+ViewPager實現滑動選單的佈局。如下圖所示:
4、側滑控制元件NavigationLayout一共包含兩個控制元件,一是頭佈局HeaderView,二是下方選單佈局menu。下面是設定NavigationLayout的佈局程式碼:
<android.support.design.widget.NavigationView
android:layout_width="320dp"
android:layout_height="match_parent"
android:id="@+id/design_navigation_view"
app:headerLayout="@layout/layout_header" //引入頭佈局檔案
app:menu="@menu/menu_left" //引入menu資料夾下的menu檔案
android:layout_gravity="start"> //設定其從左邊滑出
</android.support.design.widget.NavigationView>
NavigationLayout的頭部以及選單中的各項均可以單獨設定點選事件,設定方法如下:
//分別獲取HeaderView以及選單中的Item以及為他們註冊點選事件
@BindView(R.id.design_navigation_view)
NavigationView mNavigationView;
private View HeaderView;
HeaderView = mNavigationView.getHeaderView(0); //獲取頭部對應的View
HeaderView.setOnClickListener(new View.OnClickListener(){ //為頭部註冊點選事件
@Override //新增具體點選頭部的事件處理邏輯
public void onClick(View v) {
}
});
//為選單中各項註冊點選事件,注意要先獲取到各個item的id,根據id來判斷執行哪一段程式碼
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener(){
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
switch (id){
case R.id.menu_app_update: //新增相應點選menu_app_update的處理程式碼
break;
case R.id.menu_message://新增相應點選menu_message的處理程式碼
break;
case R.id.menu_setting://新增相應點選menu_setting的處理程式碼
break;
}
return false;
}
});
3.使用ToolBar代替ActionBar,與側滑選單進行整合
要使用ToolBar,必須先了解清楚預設使用的ActionBar。ActionBar是開發安卓軟體時預設使用的一個佈局頭部,一般只顯示一段固定的文字,也有一些擴充套件的顯示按鈕等功能。首先我們看看AndroidManifest檔案中的如下程式碼:
<application
android:allowBackup="true" //表示允許在adb除錯下,不獲取root許可權就能備份資料
android:icon="@mipmap/ic_launcher"//設定應用圖示
android:label="@string/app_name"//設定應用名稱
android:supportsRtl="true"//設定支援強制從左到右佈局
android:theme="@style/AppTheme"> //關鍵在此,設定當前應用style為AppTheme
顯然我們要看看AppTheme中的程式碼:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!—在此處自定義相關屬性-->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
上面四段程式碼一共設定了四個屬性。首先設定了AppTheme繼承自系統自帶的一個主題Theme.AppCompat.Light.NoActionBar。表示是不帶ActionBar的主題。下面的元素colorPrimary表示ActionBar的背景顏色,colorPrimaryDark表示狀態列顏色,colorAccent表示強調提示顏色,比如說點選了某個按鈕,變化提示的顏色。還有一些元素比如textColorPrimary設定ActionBar中文字顏色,windowBackground設定主顯示區背景顏色等。
由於我們設定父類主題是NoActionBar,因此就可以使用自己定義的ToolBar。典型的ToolBar設定程式碼如下所示:
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tool_bar"
android:minHeight="?attr/actionBarSize" //設定最小高度為actionBarSize
android:background="?attr/colorPrimary" //背景顏色為colorPrimary,可以修改
app:title="@string/app_name" //ToolBar文字設定為string資源中的app_name
app:titleTextColor=”@color/mywhite” //設定標題顏色為白色
android:theme="@style/AppTheme.ToolBar">//風格設定為style中的AppTheme.ToolBar
</android.support.v7.widget.Toolbar>
其中,AppTheme.ToolBar單獨設定了ToolBar的Navigation圖示以及圖示的顏色,程式碼如下:
<style name="AppTheme.ToolBar" parent="AppTheme">
<item name="drawerArrowStyle">@style/AppTheme.DrawerArrowToggle</item>
<item name="android:windowActionBarOverlay">@style/ActionButton.Overflow</item>
<item name="actionOverflowButtonStyle">@style/ActionButton.Overflow</item>
</style>
<style name="ActionButton.Overflow"parent="android:style/Widget.Holo.Light.ActionButton.Overflow">
<item name="android:src">@mipmap/ic_menu_more_overflow</item>
</style>
<style name="AppTheme.DrawerArrowToggle" parent="Base.Widget.AppCompat.DrawerArrowToggle">
<item name="color">@android:color/white</item>
</style>
ToolBar在xml檔案中定義好後,要在activity程式碼檔案中獲取到該控制元件,為其載入選單,初始化狀態,設定監聽等。ToolBar的選單佈局檔案也是在menu中設定,注意menu中的各個item可以設定其showAsAction屬性。always表示永遠顯示在ToolBar中,ifRoom表示有空間時顯示,never則表示隱藏在選單之中。
@BindView(R.id.tool_bar) Toolbar mToolbar; mToolbar.inflateMenu(R.menu.toolbar_menu); //為ToolBar設定右邊選單 ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle (this,mDrawerLayout, mToolbar, R.string.open, R.string.close); drawerToggle.syncState(); mDrawerLayout.addDrawerListener(drawerToggle);//設定監聽
注意,之前單獨為DrawerLayout設定了監聽事件,現在可以直接將drawerToggle作為監聽器傳給DrawerLayout的例項。
4. TabLayout+ViewPager+Fragment實現可滑動的頂部選單
在ToolBar下是本應用的內容顯示介面。一共分為四個部分,利用TabLayout來實現這四個標籤,利用ViewPager+Fragment實現下方四個顯示區域。其中,TabLayout是與ViewPager繫結的,通過Tablayout的setupWithViewPager(viewpager)方法就能將兩者繫結,當viewpager發生改變時,就實時更新到上方的TabLayout。下面是具體的實現步驟:
1、 在ToolBar下方新增好TabLayout以及ViewPager。程式碼如下:
android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tab_layout"
<!-- fixed表示,如果有更多的內容則可以一直向右滑出螢幕範圍-->
app:tabMode="fixed">
</android.support.design.widget.TabLayout>
<!-- 下面是設定ViewPager-->
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/view_pager">
</android.support.v4.view.ViewPager>
2、在activity檔案中,獲取到TabLayout以及ViewPager的控制元件例項。首先要為ViewPager設定內容介面卡,使用的是setAdapter(adapter)方法。其次要將ViewPager與TabLayout繫結起來。下面是設定程式碼:
1 PagerAdapter adapter = new ViewPageAdapter(getSupportFragmentManager()); 2 mViewPager.setAdapter(adapter);//為mViewPager設定內容介面卡 3 mTabLayout.setupWithViewPager(mViewPager);//將ViewPager與mTabLayout繫結
接下來詳細講述,ViewPager的內容介面卡adapter的建立方法。
ViewPager下面的內容是四個碎片,每個碎片中分別顯示相應內容。首先ViewPager要繼承FragmentStatePagerAdapter(相對於FragmentPagerAdapter,當page不為使用者所見時,僅僅保留該碎片的狀態,能夠以較小的記憶體代價維持資訊顯示)。下面根據實際程式碼進行分析:
public class ViewPageAdapter extends FragmentStatePagerAdapter { //建立FragmentInfo的List來儲存相應的碎片資訊(為什麼不是Fragment下面再談) private List<FragmentInfo> mFragments = new ArrayList<>(4); //有參建構函式,接收一個碎片管理物件FragmentManager public ViewPageAdapter(FragmentManager fm){ super(fm); initFragment(); } private void initFragment(){ //將具體的碎片新增到mFragments中,新增順序決定了顯示順序 mFragments.add(new FragmentInfo("推薦",RecommendFragment.class)); mFragments.add(new FragmentInfo ("排行", RankingFragment.class)); mFragments.add(new FragmentInfo ("遊戲", GamestFragment.class)); mFragments.add(new FragmentInfo ("分類", CategortFragment.class)); } /*getItem()是繼承自FragmentStatePagerAdapter必須要重寫的方法,根據位置返回Fragment。可以推測,將此內容介面卡傳入ViewPager時,肯定會呼叫這個方法,分別獲取到四個碎片物件,從而將內容適配好。 */ @Override public Fragment getItem(int position) { try { return (Fragment)mFragments.get(position).getFragment(). newInstance(); //返回對應位置的碎片的例項。 } catch (InstantiationException e) { e.printStackTrace(); }catch (IllegalAccessException e){ e.printStackTrace(); } return null; } //也是必須重寫的方法,可以確定到底有幾個碎片,方便getItem()方法知道範圍 @Override public int getCount() { return mFragments.size(); } //必須重寫的方法,TabLayout會呼叫這個方法來獲取各個page的名稱,即碎片名稱。 @Override public CharSequence getPageTitle(int position) { return mFragments.get(position).getTitle(); } }
下面根據FragmentInfo的程式碼來分析,為何不用直接用Fragment的List而是用FramentInfo。
public class FragmentInfo { private String title; private Class fragment; //建構函式接收title以及Class物件,傳入的Class一般都是繼承Fragment的類 public FragmentInfo( String title,Class fragment) { this.fragment = fragment; this.title = title; } public Class getFragmet() { return fragment; } public String getTitle() { return title; } }
假如在ViewPagerAdapter的List設定為Fragment,那麼的確是可以往list裡面傳入四個繼承自Fragment的具體碎片物件。但是問題隨之而來,就是怎麼重寫getPageTitle()方法?因為mFragment.getPosition(i)方法返回的是一個以Fragment為型別的Fragment型別物件。要通過父類Fragment去訪問子類中的屬性自然是很麻煩,因此此處就使用FragmentInfo作為中間類,其儲存了一個Class以及一個title。同時將ViewPagerAdapter的List設定為FragmentInfo。在往List裡面add FragmentInfo時,只需要指定好title,同時傳入各個碎片類對應的Class作為FragmentInfo的碎片標識。在getItem()方法中,再將各個碎片利用Class類的無參構造方法newInstance()來呼叫Fragment的無參構造方法例項化各個碎片。
通過這種方式,我們不用修改各個Fragment的原始檔,可以再新增FragmentInfo的時候指定其PageTitle,方便實用。