Доброго времени суток, уважаемые читатели.

Захотелось мне немного поделиться своими мыслями по поводу android разработки. Возникла у меня задача сделать настройку размера шрифта в приложении, чтобы каждый пользователь сам мог подобрать под себя размер.

Изменение размера шрифта решил делать во всех TextView и EditText, которые есть в приложении. Но использовать метод setTextSize в каждом activity не вариант, т.к. в один прекрасный момент появится новое поле и придется на нем вновь прописывать нужный размер. Поэтому, решением было сделать автоматическое изменение во всех местах.

Вся суть заключается в том, что в настройках приложения будем хранить коэффициент увеличения шрифта. Этот коэффициент будем применять на реальный размер шрифта в своем собственном классе, наследованным от TextView.

Начнем с того, что в нужном месте приложения добавим функционал выбора и сохранения коэффициента:

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();

Естественно new_coef нужно заполнять динамически. Например при выборе значения на бегунке.

Далее этот коэффициент необходимо считать в нужном месте и с помощью него изменять размер шрифта. Каждый раз считывать его из настроек приложения, при активации того или иного TextView, не совсем хорошее решение. Поэтому коэффициент будем считывать один раз при активации приложения и хранить в глобальной переменной. Для этого добавим новый класс приложения:

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

Далее в файле манифеста укажем новый наш класс:

<application
  android:name=".MyApp"
  android:icon="@drawable/ic_launcher"
  android:label="@string/app_name"
  android:theme="@style/AppTheme" >

После этого необходимо создать еще один класс, но уже на основе TextView:

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

Обратите внимание на то, что у метода setTextSize первый параметр по умолчанию = TypedValue.COMPLEX_UNIT_SP. Что означает установку размера шрифта в sp единицах измерения. В нашем же случае используется TypedValue.COMPLEX_UNIT_PX. Этот тип необходимо указывать, чтобы задать размер шрифта в пикселях, т.к. getTextSize возвращает текущий размер в пикселях.

В принципе все подготовительные классы готовы. Осталось в нужном месте разметки вместо TextView указать свой собственный класс MyTextView:

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

В итоге при открытии activity у данного текста будет изменен размер шрифта на тот, что выбрал пользователь. С EditText все делается аналогично.

Всем спасибо за внимание.

Комментарии (12)


  1. Ganster41
    06.02.2018 01:18

    А чем не угодило изменение поля Configuration.fontScale для всего приложения, без использования вороха кастомных вьюх?


    1. Zhenika Автор
      06.02.2018 06:20

      Configuration.fontScale зависит от настроек всего телефона. Если в них пользователь изменил размер шрифта, то тогда и в приложении изменится размер. Такой способ мне не подошёл, т.к. не всегда пользователь меняет размер во всем телефоне, а хочет его изменить только в конкретном приложении.


      1. Ganster41
        06.02.2018 16:15
        +1

        Так меняйте конфигурацию ресурсов для своего приложения. Примеров в всети куча.


        1. Zhenika Автор
          06.02.2018 17:55

          Если вам не сложно, то не могли бы вы скинуть ссылку на пример? Я пока ничего подходящего не смог найти. И тем более ресурсы же нельзя менять, они встраиваются в приложение в момент компиляции (это на сколько я знаю)


          1. Ganster41
            06.02.2018 18:43

            Я, например, таким образом локаль в приложении менял:

            Resources resources = getApplicationContext().getResources();
            Configuration configuration = resources.getConfiguration();
            configuration.locale = new Locale(lang);
            resources.updateConfiguration(configuration, resources.getDisplayMetrics());

            Хотя сейчас погуглил, оказывается если targetApiLevel > 17, то могут быть разные вариации. Можно почитать тут.


            1. Zhenika Автор
              06.02.2018 19:23

              Пожалуй вы правы, таким образом можно обойтись без кастомных View и application. Большое спасибо вам за подсказку.


  1. DZVang
    06.02.2018 08:04

    По-моему так себе способ. Это же нужно каждую вьюху переопределять. Самый простой способ, который приходит в голову это переопределить фактори для инфлейтера и реализовать там всю логику, тогда шрифт будет везде изменяться и никаких кастомных вьюх не нужно.


    1. Zhenika Автор
      06.02.2018 09:55

      Спасибо за идею, попробую с таким способом сделаю


      1. DZVang
        06.02.2018 14:15

        Еще можно попробовать через темы сделать, но для этого, наверное, для каждого размера шрифта в теме атрибут нужно будет создать.


        1. Zhenika Автор
          06.02.2018 15:04

          Вариант с темами я сразу исключил для себя, т.к. не хотелось делать несколько тем и потом их связывать с конкретной величиной размера шрифта. Хотелось сделать именно функционал, чтобы пользователь могу выбрать размер не из выпадающего списка, грубо говоря, а двигая ползунок.


    1. juztoss
      06.02.2018 15:02

      Использовали на проекте эту либу github.com/chrisjenx/Calligraphy

      Если не ошибаюсь, в ней так и сделано.


  1. Zhenika Автор
    06.02.2018 09:55

    Спасибо за идею, попробую с таким способом сделаю