📜 ⬆️ ⬇️

Dynamic font size change throughout an Android application using Configuration.fontScale

Good day, dear readers.

I wanted to share my thoughts about android development a bit. My task arose to make setting the font size in the application so that each user could choose the size for himself.

Changing the font size decided to do throughout the application. But using the setTextSize method in each activity is not an option, since at one point, a new field will appear and it will be necessary to re-register the required size on it. Therefore, the decision was to make an automatic change in all places.

When I wrote this article, the essence was as follows: in the settings of the application, the font increase factor is stored. This factor is applied to the actual font size in its own class, inherited from TextView. But Ganster41 suggested a better solution. Therefore, first there will be a description of the original solution, and at the end there will be an implementation using Configuration.fontScale .
')

Initial implementation


Let's start with the fact that in the right place of the application we add the functionality of selecting and saving the coefficient:
Code
float new_coef = 1.3f; //  SharedPreferences settings = getSharedPreferences("MyAppSett", MODE_PRIVATE); Editor value_add = settings.edit(); //     value_add.putFloat("size_coef", new_coef); value_add.commit(); 


Naturally new_coef needs to be filled dynamically. For example, when choosing a value on the slider.

Further, this coefficient should be considered in the right place and with the help of it change the font size. Every time reading it from the application settings, when activating a TextView, is not a very good solution. Therefore, the coefficient will be read once when the application is activated and stored in a global variable. To do this, add a new application class:
Code
 package com.Example.Test; import android.app.Application; import android.content.SharedPreferences; public final class MyApp extends Application { private float size_coef; //   //    public float getSizeCoef() { return size_coef; } //  @Override public void onCreate() { super.onCreate(); //    SharedPreferences settings = getSharedPreferences("MyAppSett", MODE_PRIVATE); size_coef= settings.getFloat("size_coef", 1f); } } 


Further, in the manifest file, we indicate our new class:
Code
 <application android:name=".MyApp" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > 


After that, you need to create another class, but based on the TextView:
Code
 package com.Example.Test; import android.app.Activity; import android.content.Context; import android.support.v7.widget.AppCompatTextView; import android.util.AttributeSet; import android.util.TypedValue; //     public final class MyTextView extends AppCompatTextView { //  public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); InitSize(context); } //   private void InitSize(Context context) { //    Activity activity = (Activity) context; float koef = ((MyApp) activity.getApplication()).getSizeCoef(); float cur_size = getTextSize(); //     //      setTextSize(TypedValue.COMPLEX_UNIT_PX, cur_size * koef); } } 


Note that the setTextSize method has the first default parameter = TypedValue.COMPLEX_UNIT_SP . Which means setting the font size in sp units. In our case, TypedValue.COMPLEX_UNIT_PX is used. This type must be specified to set the font size in pixels, since getTextSize returns the current size in pixels.

In principle, all the preparatory classes are ready. It remains in the right place markup instead of TextView to specify your own class MyTextView:
Code
 <com.Example.Test.MyTextView android:id="@+id/TextValue" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/TextColor" android:textSize="@dimen/TextSize" /> 


As a result, when you open the activity for this text, the font size will be changed to the one that the user has selected. With EditText, everything is done similarly.

Updated implementation


For myself, I decided to use the font size factor from 0.7f to 1.45f with an interval of 0.15f . Those. these are 6 steps. To select a specific value using SeekBar .
 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:progress="0" android:max="5" /> </LinearLayout> 

In the right place of the application (in the onCreate method) we implement the processing of the selected value on the SeekBar:
 final float start_value = 0.7f; //    final float step = 0.15f; //   int size_coef; //  ... SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar); ... if (seekBar != null) { seekBar.setProgress(select_coef); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { size_coef = progress; //  } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } 

The value selection processing on the slider is done. Now you need to save the selected result and immediately change the font size (for example, by using the button):
 //  SharedPreferences settings = getSharedPreferences("MyAppSett", MODE_PRIVATE); SharedPreferences.Editor value_add = settings.edit(); //     value_add.putInt("size_coef", size_coef); value_add.apply(); //     Resources res = getResources(); float oef = start_value + size_coef * step; //    Configuration configuration = new Configuration(res.getConfiguration()); configuration.fontScale = oef; res.updateConfiguration(configuration, res.getDisplayMetrics()); 

Now when you change the activity will be the new font size in all places of the application. But at the moment this size will be only until the application is restarted. When you open the application, the font size of what is set in the android settings on the device will be set. And accordingly, in order for the size we need in the application, it is necessary to reassign it. To do this, we save the coefficient in the application parameters:
 package com.Example.Test; import android.app.Application; import android.content.SharedPreferences; public final class MyApp extends Application { //  @Override public void onCreate() { super.onCreate(); int size_coef; final float start_value = 0.7f; //    final float step = 0.15f; //   Resources res = getResources(); SharedPreferences settings = getSharedPreferences("MyAppSett", MODE_PRIVATE); try { //    size_coef = settings.getInt("size_coef", 2); } catch (Exception e) { size_coef = 2; //   } //    float new_value = start_value + size_coef * step; //     Configuration configuration = new Configuration(res.getConfiguration()); configuration.fontScale = new_value; res.updateConfiguration(configuration, res.getDisplayMetrics()); } } 

The default value is 2 , i.e. in my formula, this is a font increase factor of 1 (0.7 + 0.15 * 2 = 1). This class must be specified in the manifest:
 <application android:name=".MyApp" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > 

As a result, when you open the application, the font size will be changed in all places. I redid my implementation from the first method to the second, which made it possible not to add my own classes for TextView, EditText, etc.

Thank you all for your attention.

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


All Articles