Android 设置主题的方法

很多应用都提供设置主题的功能, 这里介绍一种设置主题的方法. 这种方法通过设置一个基类Activity来管理主题切换的功能, 然后所有的activity继承它, 并实现其中切换主题的接口, 那么所有的Activity也就具有了主题切换的功能. 效果如下:

1.首先创建一个主题设置的工具类Theme, 这里为了简单用了数字来标识主题类型, 实际中可以将主题类型用SharedPreferences来保存.

public class Theme {

    private int pos;
    private Context context;
    private static Theme mTheme;

    static Theme getInstance(Context context) {
        if (mTheme == null) {
            synchronized (Theme.class) {
                if (mTheme == null)
                    mTheme = new Theme(context);
            }
        }
        return mTheme;
    }

    private Theme(Context context) {
        this.context = context;
        this.pos = 1;
    }

    public void updateTheme(int pos) {
        this.pos = pos;
    }

    private int getColor(@ColorRes int color) {
        return ContextCompat.getColor(context, color);
    }

    public int getBackgroundColor(){
        switch (pos){
            case 2:
                return getColor(R.color.md_black_1000);
            case 1:
            default:
                return getColor(R.color.md_light_1000);
        }
    }

    public int getTextColor() {
        switch (pos){
            case 2:
                return getColor(R.color.md_light_1000);
            case 1:
            default:
                return getColor(R.color.md_grey_800);
        }
    }
}

2.创建接口Themeable, 来实现所有自定义View具备换主题的功能, 接口很简单, 只有一个方法

public interface Themeable {
    void resetTheme(Theme theme);
}

3.建立一个ThemeActivity, 让所有的Activity继承它, 这样所有的Activity就有了设置主题的功能.
ThemeActivity的代码如下:

public class ThemedActivity extends AppCompatActivity {

    private Theme mTheme;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTheme = Theme.getInstance(getApplicationContext());
    }

    @Override
    protected void onResume() {
        super.onResume();
        updateUiElements(); //在onRsume中调用updateUiElements这样保证继承自
                            // ThemeActivity的activity都能自动切换主题
    }
    //更新主题类型
    public void setBaseTheme(int pos) {
        mTheme.updateTheme(pos);
    }

    public void updateUiElements() {
        List<View> viewList = getAllChildren(findViewById(android.R.id.content));
        for (View view : viewList) {
            if (view instanceof Themeable) //这里确保所有继承自Themeable的View能自动切换主题
                ((Themeable) view).resetTheme(mTheme);
        }
    }

    private List<View> getAllChildren(View target) {
        if (!(target instanceof ViewGroup))
            return Collections.singletonList(target);

        ArrayList<View> allChildren = new ArrayList<>();
        ViewGroup viewGroup = (ViewGroup) target;
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View child = viewGroup.getChildAt(i);
            ArrayList<View> targetsChildren = new ArrayList<>();
            targetsChildren.add(target);
            targetsChildren.addAll(getAllChildren(child));
            allChildren.addAll(targetsChildren);
        }
        return allChildren;
    }

    public int getTextColor() {
        return mTheme.getTextColor();
    }

    public int getBackgroundColor() {
        return mTheme.getBackgroundColor();
    }
}

4.这里为了测试提供一个MainActivity与SettingActivity, 都继承与ThemeActivity, 实现updateUiElements接口, 不同Activity根据主题的类型在此接口中进行设置, 这样就实现不同的Activity实现主题切换, 代码如下:

public class MainActivity extends ThemedActivity {

    private RelativeLayout mRelativeLayout;
    private TextView mTextView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRelativeLayout = (RelativeLayout) findViewById(R.id.activity_main);
        mTextView = (TextView) findViewById(R.id.main_text_view);
        mTextView.setText(
                "人生若只如初见,何事秋风悲画扇。\n" +
                "等闲变却故人心,却道故人心易变。\n" +
                "骊山语罢清宵半,泪雨零铃终不怨。\n" +
                "何如薄幸锦衣郎,比翼连枝当日愿。");

        Button btnTheme = (Button) findViewById(R.id.btn_setting_theme);
        btnTheme.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SettingActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    public void updateUiElements() {
        super.updateUiElements();
        //根据主题类型设置背景与字体颜色
        mRelativeLayout.setBackgroundColor(getBackgroundColor());
        mTextView.setTextColor(getTextColor());
    }
}
public class SettingActivity extends ThemedActivity {

    private RelativeLayout mRelativeLayout;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_setting);
        mRelativeLayout = (RelativeLayout) findViewById(R.id.activity_setting);
        SettingView view1 = (SettingView) findViewById(R.id.theme_setting_view_1);
        view1.setTitleViewText("主题1");
        view1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //切换到主题1
                setBaseTheme(1);
                updateUiElements();
            }
        });

        SettingView view2 = (SettingView) findViewById(R.id.theme_setting_view_2);
        view2.setTitleViewText("主题2");
        view2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //切换到主题2
                setBaseTheme(2);
                updateUiElements();
            }
        });
    }

    @Override
    public void updateUiElements() {
        super.updateUiElements();
        //根据主题类型设置背景
        mRelativeLayout.setBackgroundColor(getBackgroundColor());
    }
}

在SettingActivity中为了展示Themeable, 添加自定义SettingView来设置主题样式. SettingView实现Themeable接口, 代码如下:

public class SettingView extends FrameLayout implements Themeable {

    public SettingView(Context context) {
        this(context, null);
    }

    public SettingView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SettingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        LayoutInflater inflater = LayoutInflater.from(getContext());
        inflater.inflate(R.layout.setting_view, this);
    }

    public void setTitleViewText(CharSequence text) {
        ((TextView)findViewById(R.id.title)).setText(text);
    }
    @Override
    public void resetTheme(Theme theme) {
        //根据主题类型设置自定义view的样式
        findViewById(R.id.ll_setting_view).setBackgroundColor(theme.getBackgroundColor());
        ((TextView)findViewById(R.id.title)).setTextColor(theme.getTextColor());
        ((TextView)findViewById(R.id.caption)).setTextColor(theme.getTextColor());
    }
}

在ThemeActivity的updateUiElements接口中会去遍历所有继承自Themeable的view, 调用其resetTheme接口, 这样SettingView就能根据选择的主题类型进行切换.

示例代码可以从这里获得切换主题示例Demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值