1. 程式人生 > >我的手機助手開發日誌---1

我的手機助手開發日誌---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,方便實用。