前言
??上一篇文章中枉阵,將一些系統(tǒng)的 View 已經(jīng)完成換膚了译红。這篇文章我們會完成 Fragment、狀態(tài)欄兴溜、底部虛擬按鍵的換膚侦厚。
Fragment 換膚
??我們需要使用到 TableLayout,所以添加一個(gè)依賴
compile 'com.android.support:design:26.+'
拙徽,然后修改 MainActivity 的布局文件刨沦,并修改 MainActivity 給其添加幾個(gè) Fragment
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="?attr/colorAccent">
<TextView
android:id="@+id/tv_click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="換膚"
android:padding="10dp"
android:background="#ffffff"
android:layout_marginBottom="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_other"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textColor="@color/black"
android:text="還原"
android:background="@color/black"/>
<TableLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
</TableLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//...
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabLayout);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
List<Fragment> list = new ArrayList<>();
list.add(new MusicFragment());
list.add(new VideoFragment());
list.add(new RadioFragment());
List<String> listTitle = new ArrayList<>();
listTitle.add("音樂");
listTitle.add("視頻");
listTitle.add("電臺");
MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter
(getSupportFragmentManager(), list, listTitle);
viewPager.setAdapter(myFragmentPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
}
??這里新建了幾個(gè) Fragment 并且顯示在 Activity 中,我們測試一下前面寫的系統(tǒng)的 View 換膚能否在 Fragment 里面進(jìn)行換膚
??點(diǎn)擊換膚按鈕
??我們發(fā)現(xiàn)膘怕,F(xiàn)ragment 里面也可以進(jìn)行換膚想诅,為什么呢?
??一個(gè) Fargment 里面岛心,我們重寫它的 onCreateView 方法后来破,onCreateView 方法里面的 LayoutInflater 會通過參數(shù)傳遞過來,我們通過查看 Fragment 的源碼會發(fā)現(xiàn)忘古,這個(gè) LayoutInfalter 是通過 mHost.onGetLayoutInflater(); 獲取的
??而我們的 Activity 繼承自
??在這個(gè) FragmentActivity 里面
??所以我們調(diào)用的是這個(gè) HostCallbacks 的 onGetLayoutInflater 方法
??通過一個(gè) cloneInContext 方法獲取的一個(gè) Activity讳癌,所以說跟 Activity 的 LayoutInflater 不是同一個(gè) LayoutInflater,而其實(shí)我們拿到的是 LayoutInflater 的子類:PhoneLayoutInflater
??這是 new 出來的存皂,所以跟 Activity 的 Inflater 不是同一個(gè)晌坤,我們繼續(xù)看 PhoneLayoutInflater 的構(gòu)造函數(shù)
??他會調(diào)用父類的構(gòu)造函數(shù)
??原來是這樣,里面的 mFactory 旦袋、mFactory2 是同一個(gè)骤菠。也就是說,雖然 Fragment 的 LayoutInflater 跟我們的 Activity 的 LayoutInflater 不是同一個(gè)疤孕,但是他們里面的 Factory 是同一個(gè)商乎。
??也許細(xì)心的同學(xué),會看見這一行代碼
??這一行代碼就設(shè)置 Factory2祭阀,那我們設(shè)置了 Factory2 他也設(shè)置了 Factory2 為什么會用到我們的鹉戚?原因是這里面他使用了工廠合并鲜戒,我們看下面的源碼
??所以說,最終還是會回調(diào)到我們自定義的 Factory2 里面抹凳,那這也就解釋了為什么我們沒有給 Fragment 做任何操作遏餐,F(xiàn)ragment 就能換膚的原因。
狀態(tài)欄和底部虛擬按鍵換膚
??我們先看一張圖
??很多人都見過這張圖赢底,狀態(tài)欄是由 statusBarColor 和 colorPrimaryDark 來控制失都,底部虛擬按鍵是由 navigationBarColor 來控制的。
注意:其中 colorPrimaryDark 的全路徑是:
android.support.v7.appcompat.R.attr.colorPrimaryDark
statusBarColor 的全路徑是:android.R.attr.statusBarColor
navigationBarColor 的全路徑是:android.R.attr.navigationBarColor
??狀態(tài)欄換膚和底部虛擬按鍵換膚有對應(yīng)的 api 可以調(diào)用幸冻,但是需要在 Android 5.0 版本以上才可以粹庞。注意狀態(tài)欄的配置有兩個(gè),我們優(yōu)先從 statusBarColor 里面去找洽损,如果沒找到就去 colorPrimaryDark 中找庞溜。
??在 SkinThemeUtils 增加如下方法
/**
* 狀態(tài)欄、底部虛擬按鈕換膚
*/
public static void updateStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return ;
}
int[] resId = getResId(activity, STATUSBAR_COLOR_ATTRS);
if(resId[0] == 0){
resId[0] = getResId(activity,APPCOMPAT_COLOR_PRIMARY_DARK_ATTR)[0];
}
//更換狀態(tài)欄
if(resId[0] != 0){
activity.getWindow().setStatusBarColor(SkinResources.getInstance().getColor(resId[0]));
}
//更換底部虛擬按鍵
if(resId[1] != 0){
activity.getWindow().setNavigationBarColor(SkinResources.getInstance().getColor(resId[1]));
}
}
??然后我們在我們的主包下面添加如下代碼
??這樣我們確保就能在 Android 5.0 系統(tǒng)以上的手機(jī)可以使用使用 navigationBarColor 這個(gè)屬性并且可以進(jìn)行換膚碑定。然后我們把皮膚包中的 colorPrimaryDark 設(shè)置成白色流码,也就是最終換膚后系統(tǒng)狀態(tài)欄和底部虛擬按鍵的背景色都換成了白色。
??最后不傅,就是要調(diào)用狀態(tài)欄換膚的功能了旅掂。分別在 Activity 創(chuàng)建的時(shí)候以及我們點(diǎn)擊換膚按鈕的時(shí)候調(diào)用一次即可。