切换主题时如何考虑变化?

时间:2018-02-14 07:33:22

标签: java android dynamic themes

我正在使用Android应用程序,该应用程序需要根据服务器提供的themeCode切换主题。我使用sharePref保存主题代码并将其应用于setTheme(R.style.themeName);。它的工作正常,直到

等基本主题属性
colorPrimary
colorPrimaryDark
colorAccent
windowActionBar
windowNoTitle

为此我在styles.xml创建了不同的样式。但我有一个限制,有些字段说EditText的变体为EditText

  • 人名
  • 电子邮件
  • 电话
  • 密码等。

类似地,TextView具有TextView

的变体
  • 标题
  • 单行
  • Mutiline
  • 链接等。

在多主题要求之前,我为所有人创建了单独的主题

  • Apptheme.Edittext.email
  • Apptheme.Edittext.Password
  • Apptheme.Edittext.PersonName等 并且正在应用于xml中的特定视图,如

     style="@style/AppTheme.EditText.PersonName"  
    

现在我查看过很多教程/帖子,但没有找到属性变体的解决方案。请帮助应用这些变化,我将为此感恩。

问候: Inzimam Tariq

2 个答案:

答案 0 :(得分:1)

在我看来,在运行时更改应用主题,肯定需要重新加载活动;在大多数情况下,这会在某些时候产生问题(如果项目扩展到中等规模,具有用户控制,如切换或切换,如果用户重复切换应用可能很容易崩溃)

我建议使用自定义控件类(Textviews,Buttons..etc);其中,此属性使用sharedPref中的当前主题值进行区分。 这种方法有一个con;它需要手动更改当前屏幕的所有视图和已经在内存中渲染的视图(如果有的话),与传统方法相比,它将更加平滑过渡

编辑:CustomTextView ##

的示例

这是customtextview类

的示例
public class CustomTextView extends android.support.v7.widget.AppCompatTextView {
private static final String TAG = "TextView";
private Typeface tf = null;
private SharedPreferenceUtils preferenceUtils = SharedPreferenceUtils.getInstance();

/**
 * @param context:This is an abstract class whose implementation is provided by Android Operating System.
 * @param attrs:A      collection of attributes, as found associated with a tag in an XML document.
 * @param defStyle:
 */
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    if (preferenceUtils.getBooleanValue(PrefsKeyValue.bTheme)) {
        this.setTextColor(ResourceUtils.getColor(R.color.lightThemeTextColor));
    } else {
        this.setTextColor(ResourceUtils.getColor(R.color.colorWhite));
    }

    try {
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.CustomEditText, defStyle, 0);

        String str = a.getString(R.styleable.CustomTextView_FontEnum);
        int original = a.getInt(R.styleable.CustomEditText_FontEnum, 0);
        CustomEnum.CustomFontType customEnumValue = CustomEnum.CustomFontType.fromId(a.getInt(R.styleable.CustomEditText_FontEnum, 0));
        a.recycle();
        switch (customEnumValue) {
            case BOLD:
                setTypeface(HelveticaNeueBold.getInstance(context).getTypeFace());
                break;

            case LIGHT:
                setTypeface(HelveticaNeueMedium.getInstance(context).getTypeFace());
                break;

            case REGULAR:
                setTypeface(HelveticaNeue.getInstance(context).getTypeFace());
                break;

            default:
                break;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public CustomTextView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}


public boolean setCustomFont(Context ctx, String asset) {

    try {
        tf = Typeface.createFromAsset(ctx.getAssets(), asset);
    } catch (Exception e) {
        LogUtils.LogE(TAG, "Could not get typeface: " + e.getMessage());
        return false;
    }

    setTypeface(tf);
    return true;
}}

此处我已根据sharedPref

中的主题值更改了textcolor
 if (preferenceUtils.getBooleanValue(PrefsKeyValue.bTheme)) {
        this.setTextColor(ResourceUtils.getColor(R.color.lightThemeTextColor));
    } else {
        this.setTextColor(ResourceUtils.getColor(R.color.colorWhite));
    }

然后在xml文件中将此类用作textview标记。

    <com.mypkg.customview.CustomTextView
    style="@style/signup_textViewStyle"
    android:text="@string/activity_login_password" />

我相信,你可以用相同的方式处理控件主题的属性变化。

答案 1 :(得分:0)

您可以为视图类型创建自定义属性(例如TextView.PersonTextView.Date ...),在xml中,您可以引用属性,然后在不同的主题中定义属性。例如,style.xml可以是

<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" >
        <item name="TextView.Date">@style/DateTextViewDefault</item>
    </style>

    <style name="DateTextViewDefault">
        <item name="android:textColor">#ff333333</item>
        <item name="android:fontFamily">monospace</item>
    </style>

    <!-- Theme A -->
    <style name="AppTheme.A">
        <item name="colorPrimary">#3F51B5</item>
        <item name="colorPrimaryDark">#303F9F</item>
        <item name="colorAccent">#FF4081</item>
        <item name="TextView.Person">@style/PersonTextViewA</item>
    </style>

    <style name="PersonTextViewA">
        <item name="android:textSize">16sp</item>
        <item name="android:fontFamily">serif</item>
        <item name="android:textColor">#ff999999</item>
    </style>

    <!-- Theme B -->
    <style name="AppTheme.B">
        <item name="colorPrimary">#888888</item>
        <item name="colorPrimaryDark">#555555</item>
        <item name="colorAccent">#000000</item>
        <item name="TextView.Person">@style/PersonTextViewB</item>
        <item name="TextView.Date">@style/DateTextViewB</item>
    </style>

    <style name="PersonTextViewB">
        <item name="android:textSize">20sp</item>
        <item name="android:fontFamily">monospace</item>
        <item name="android:textColor">#ff55aa</item>
    </style>

    <style name="DateTextViewB">
        <item name="android:textColor">#ff0000BB</item>
        <item name="android:fontFamily">sans-serif</item>
    </style>

    <attr name="TextView.Person" format="reference" />
    <attr name="TextView.Date" format="reference" />

</resources>

然后你的活动xml布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        style="?attr/TextView.Person"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="John Doe" />

    <TextView
        style="?attr/TextView.Date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="31/12/1999" />

    <Button
        android:id="@+id/buttonA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="THEME A" />

    <Button
        android:id="@+id/buttonB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="THEME B" />

</LinearLayout>

请注意TextView的样式是

style="?attr/TextView.Person"

style="?attr/TextView.Date"

AppTheme.AAppTheme.B对这些属性有两种不同的分辨率

在此示例中,属性是视图的整个样式,但您可以轻松地为每种视图类型(TextView.person)设置一种样式,然后为该样式的单个项目定义通用属性,例如。

<attr name="TextView.Person.TextColor" format="color" />

并且只更改主题中的单个属性。

然后在您的Activity中,您只需要使用onCreatesetTheme(int)中设置主题,在这种情况下,值可以是R.style.AppTheme_AR.style.AppTheme_B

使用此方法,您可以根据需要添加任意数量的样式,而无需触摸布局。此外,您始终可以在基本主题中定义一些默认样式,然后仅在某些自定义主题中覆盖该值,而其他人则使用上面示例中TextView.Date的默认样式。

如果您想快速尝试,请参阅上面Activity以及style.xmlactivity_main.xml以上的class MainActivity : AppCompatActivity() { private val prefs by lazy { getSharedPreferences("SharedPrefs", Context.MODE_PRIVATE) } private var customTheme: Int get() = prefs.getInt("theme", R.style.AppTheme_A) set(value) = prefs.edit() .putInt("theme", value) .apply() .also { recreate() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setTheme(customTheme) setContentView(R.layout.activity_main) buttonA.setOnClickListener { customTheme = R.style.AppTheme_A } buttonB.setOnClickListener { customTheme = R.style.AppTheme_B } } } 代码

Oinfo = OStatus.reduce((acc, x) => ({ ...acc, [x]: (acc[x] || 0) + 1 }), {})