How to consider variation when switching themes?

I am working on an Android application that requires switching themes based on the themeCode set from the server. I use sharePref to save the theme code and apply it using setTheme(R.style.themeName); . Its work is excellent until the main attributes of the theme look like

 colorPrimary colorPrimaryDark colorAccent windowActionBar windowNoTitle 

To do this, I created different styles in styles.xml . But I have a limitation that some fields say that EditText has a change like EditText

  • name of man
  • Email
  • telephone
  • password etc.

And similarly, TextView has a variation like TextView

  • Headline
  • Single line
  • Mutiline
  • Link etc.

Before claiming multiple tags, I created separate topics for everyone like

  • Apptheme.Edittext.email
  • Apptheme.Edittext.Password
  • Apptheme.Edittext.PersonName etc. And applied to a specific view in xml, for example

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

Now I looked through a lot of tutorials / posts, but could not find a solution for the attribute options. Please help apply these options, I will be grateful for that.

Sincerely: Inzymam Tarik

+5
source share
2 answers

What you can do is to create user-defined attributes to see what kinds of (for example, TextView.Person , TextView.Date ...), your xml you can refer to the attributes, and then define the attributes in different themes. For example, your style.xml might be

 <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> 

then your xml layout of your activity

 <?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> 

note that the TextView styles are

 style="?attr/TextView.Person" 

and

 style="?attr/TextView.Date" 

AppTheme.A and AppTheme.B have two different permissions for these attributes.

In this example, the attributes are whole styles for your views, but you can easily have one style for each type of view ( TextView.Person ), and then define common attributes for the individual elements of that style, for example.

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

and change only one attribute in your themes.

Then in your Activity you just need to set the theme in onCreate using setTheme(int) , the value can be either R.style.AppTheme_A , or R.style.AppTheme_B in this case.

With this method, you can add as many styles as you want without touching layouts. In addition, you can always define some default styles in your base theme, and then override this value in some custom themes, while others use the default value for TextView.Date in the example above.

If you want a quick try, here is the Activity code I used to test style.xml and activity_main.xml above

 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 } } } 
0
source

In my opinion, changing the theme of the application at runtime will definitely restart the activity ; this in most cases will create problems at some point (if the project is expanded to the middle scale, using a user control , for example, to switch or switch, and if the user briefly switches, it can easily fail)


I would suggest using custom control classes (Textviews, Buttons..etc); in which these properties differentiate with the current theme value from sharedPref. This approach has con; this will require changing all manually representations of the current screen and those that are already displayed in memory (if any), the rest will be a much smoother transition compared to our usual approach

EDIT: Example for CustomTextView ##

This is an example of the customtextview class

 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; }} 

Here I changed the textcolor to match the theme value from sharedPref

  if (preferenceUtils.getBooleanValue(PrefsKeyValue.bTheme)) { this.setTextColor(ResourceUtils.getColor(R.color.lightThemeTextColor)); } else { this.setTextColor(ResourceUtils.getColor(R.color.colorWhite)); } 

Then use this class as a textview tag in an XML file.

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

I believe that you can handle property changes with the theme for controls in the same way.

+1
source

Source: https://habr.com/ru/post/1275355/


All Articles