Android 使用Theme实现动态切换主题详细教程

简介:
有关于Android 实现应用内动态切换主题的常用方式有两种

通过Theme切换主题
通过AssetManager切换主题
本文主要介绍通过Theme切换主题。

通过Theme切换主题

Android 通过在activity中使用 setTheme()函数来设置背景样式,通过加载styles.xml里的样式来设置Android 应用的主题。(注意:需要在 setContentView(R.layout.activity_main);之前调用setTheme)

在开始制作主题之前我们先看下这张图
通过这张图我们可以了解到不同的字段代表的是哪一块的颜色,例如:

colorPrimary 代表的是 App Bar 的颜色。
colorPrimaryDark 代表的是状态栏的背景色。
我们也可以自己定制布局控件的颜色:

1. 在values文件夹下创建attr.xml ,在attr.xml写入属性名

<resources>
    <attr name="mainColor" format="color" />
    <attr name="view1color" format="color" />
    <attr name="view2color" format="color" />
    <attr name="view3color" format="color" />
    <attr name="button1color" format="color" />
</resources>
2. 在colors.xml 填入需要用到的颜色。

<resources>

    <color name="colorPrimary">#008577</color>
    <color name="colorAccent">#D81B60</color>
    <color name="colorPrimaryDark">#00574B</color>
    <color name="blue2">#006c93</color>
    <color name="blue1">#b4e1f1</color>
    <color name="blue3">#003CFF</color>
    <color name="blace">#000000</color>
    <color name="white">#FFFFFF</color>
    <color name="red">#fd0000</color>
    <color name="red2">#f96363</color>
    <color name="green">#04fd00</color>
    <color name="yellow">#D9B300</color>
    <color name="gray">#cecece</color>
    <color name="pink">#ff3542</color>
</resources>
3. 在布局中引用样式,注意红框圈起来的部分


4. 在styles.xml文件下自定义主题样式
在这里写个例子示范。

    <style name="AppTheme" parent="Base.Theme.AppCompat.Light.DarkActionBar" >
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>// App Bar 颜色
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>//状态栏颜色
        <item name="colorAccent">@color/colorAccent</item>//控件选中状态下的颜色
        <item name="android:windowBackground">@drawable/white</item>//窗口背景颜色
        <item name="view1color">@color/blue1</item>//textview1的颜色
        <item name="view2color">@color/red</item>//textview2的颜色
        <item name="view3color">@color/yellow</item>//textview3的颜色
        <item name="button1color">@color/blue1</item>//button的颜色
    </style>

parent 是指继承的主题风格,
常见的主题风格有:以下这些:
android:theme="@android:style/Theme.Dialog" 将一个Activity显示为能话框模式
android:theme="@android:style/Theme.NoTitleBar" 不显示应用程序标题栏
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 不显示应用程序标题栏,并全屏
android:theme=“Theme.Light” 背景为白色
android:theme=“Theme.Light.NoTitleBar” 白色背景并无标题栏
android:theme=“Theme.Light.NoTitleBar.Fullscreen” 白色背景,无标题栏,全屏
android:theme=“Theme.Black” 背景黑色
android:theme=“Theme.Black.NoTitleBar” 黑色背景并无标题栏
android:theme=“Theme.Black.NoTitleBar.Fullscreen” 黑色背景,无标题栏,全屏
android:theme=“Theme.Wallpaper” 用系统桌面为应用程序背景
android:theme=“Theme.Wallpaper.NoTitleBar” 用系统桌面为应用程序背景,且无标题栏
android:theme=“Theme.Wallpaper.NoTitleBar.Fullscreen” 用系统桌面为应用程序背景,无标题栏,全屏
android:theme=“Translucent” 半透明
android:theme=“Theme.Translucent.NoTitleBar” 半透明、无标题栏
android:theme=“Theme.Translucent.NoTitleBar.Fullscreen” 半透明、无标题栏、全屏
android:theme=“Theme.Panel”

5. 实现读取配置文件设置主题

    private  void setBaseTheme() {
        SharedPreferences sharedPreferences = getSharedPreferences(
                "com.example.test_preferences", MODE_PRIVATE);
        String themeType = sharedPreferences.getString("theme_type", "蓝色主题");
        int themeId;
        switch (themeType) {
            case "蓝色主题":
                themeId = R.style.blueTheme;
                break;
            case "粉色主题":
                themeId = R.style.pinkTheme;
                break;
            case "彩色主题":
                themeId = R.style.AppTheme;
                break;
            default:
                themeId = R.style.blueTheme;
        }
        setTheme(themeId);
    }

使用SharedPreferences 来读取文件。根据读取的参数来设置主题
再次提醒,需要写在setContentView(R.layout.activity_main);之前

Android之基于AssetManager实现换肤方案

AssetManager的addAssetPath负责将另一个apk的资源文件加载进当前应用,这里由于是api隐藏方法,采用反射方式调用。

查看addAssetPath方法注释,允许传递的路径为资源目录或者zip文件。

/**
 * Add an additional set of assets to the asset manager.  This can be
 * either a directory or ZIP file.  Not for use by applications.  Returns
 * the cookie of the added asset, or 0 on failure.
 * {@hide}
 */

通过实例化的AssetManager对象,生成插件包对应的Resources对象,拿到该对象即可操作插件包的相关资源文件。

private Resources pluginRes;//插件Resource对象
private String pluginApkPackageName;//插件Apk的包名

public ResPluginOnAssetManagerPattern initManager(Context curContext, String pluginApkPath) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, PackageManager.NameNotFoundException, ClassNotFoundException {
    AssetManager assetManager = AssetManager.class.newInstance();
    Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
    addAssetPath.invoke(assetManager, pluginApkPath);

    Resources curAppRes = curContext.getResources();
    pluginRes = new Resources(assetManager, curAppRes.getDisplayMetrics(), curAppRes.getConfiguration());
    pluginApkPackageName = UtilsSystem.getPackageNameThroughApkPath(curContext, pluginApkPath);
    return this;
}

想要获取插件包的资源,可以通过以下方式引用(这里仅给出string以及drawable的调用方式,其他资源类似):

/**
 * 获取ResID
 *
 * @param resName
 * @param resType
 * @return
 */
private int getResId(String resName, String resType) {
    if (pluginRes != null && !UtilsString.isEmptyBaseTrim(pluginApkPackageName)) {
        return pluginRes.getIdentifier(resName, resType, pluginApkPackageName);
    }
    return -1;
}

@Override
public String getString(String resName) {
    return pluginRes.getString(getResId(resName, "string"));
}

@Override
public Drawable getDrawable(String resName) {
    return pluginRes.getDrawable(getResId(resName, "drawable"));
}

源码地址:https://github.com/xiaoxuan948/AndroidUnityLab/tree/master/unity_base_dev_helper/src/main/java/com/coca/unity_base_dev_helper/plugin

参考文章:https://blog.csdn.net/qq_36674643/article/details/90546926

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现底部导航栏,可以使用 Android 中的 TabLayout 和 ViewPager。具体步骤如下: 1. 在布局文件中添加 TabLayout 和 ViewPager 组件。 2. 创建三个 Fragment,并在每个 Fragment 中添加相应的布局和逻辑。 3. 创建一个 PagerAdapter,用于将 Fragment 和 TabLayout 绑定。 4. 在 MainActivity 中设置 ViewPager 的适配器,并将 TabLayout 和 ViewPager 进行绑定。 5. 在 MainActivity 中添加底部导航栏的选项卡,并设置选项卡的图标和标签。 6. 在 MainActivity 中添加选项卡的点击事件,以便切换不同的 Fragment。 下面是一个简单的实现示例: MainActivity.java: ```java public class MainActivity extends AppCompatActivity { private TabLayout mTabLayout; private ViewPager mViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTabLayout = findViewById(R.id.tab_layout); mViewPager = findViewById(R.id.view_pager); // 创建三个 Fragment Fragment1 fragment1 = new Fragment1(); Fragment2 fragment2 = new Fragment2(); Fragment3 fragment3 = new Fragment3(); // 创建 PagerAdapter MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager()); adapter.addFragment(fragment1, "Tab 1"); adapter.addFragment(fragment2, "Tab 2"); adapter.addFragment(fragment3, "Tab 3"); // 设置 ViewPager 的适配器 mViewPager.setAdapter(adapter); // 将 TabLayout 和 ViewPager 进行绑定 mTabLayout.setupWithViewPager(mViewPager); // 设置选项卡的图标和标签 mTabLayout.getTabAt(0).setIcon(R.drawable.ic_tab1).setText("Tab 1"); mTabLayout.getTabAt(1).setIcon(R.drawable.ic_tab2).setText("Tab 2"); mTabLayout.getTabAt(2).setIcon(R.drawable.ic_tab3).setText("Tab 3"); // 添加选项卡的点击事件,以便切换不同的 Fragment mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { mViewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } }); } // 自定义 PagerAdapter private class MyPagerAdapter extends FragmentPagerAdapter { private List<Fragment> mFragmentList = new ArrayList<>(); private List<String> mTitleList = new ArrayList<>(); public MyPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } public void addFragment(Fragment fragment, String title) { mFragmentList.add(fragment); mTitleList.add(title); } @Nullable @Override public CharSequence getPageTitle(int position) { return mTitleList.get(position); } } } ``` activity_main.xml: ```xml <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:tabGravity="fill" app:tabIndicatorColor="@android:color/white" app:tabIndicatorHeight="2dp" app:tabSelectedTextColor="@android:color/white" app:tabTextColor="@android:color/white" /> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.design.widget.CoordinatorLayout> ``` 注意:上述代码使用Android Support Library,如果你使用的是 AndroidX 的话,需要将相应的组件和包名进行更改。另外,还需要在 build.gradle 文件中添加相应的依赖。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值