Is it possible to make an application-wide setting for the font-size to be used by all views displaying text? I would like to provide a Preference to the user which should allow scaling all text in the app.
Android explicitly allows using the "sp" dimension unit for scalable text, however there is no actual way to set the "user's font size preference" in a global way.
Iterating through all views on Activity instantiation is not really an option ;-)
Here it's how I made it for my app.
In a few words - in Activity.onCreate()
you get resource id of style with specific set of font sizes and apply this style to theme of activity. Then with preferences activity you can switch between these sets.
First of all in values/attrs.xml declare attributes for set of font sizes:
<declare-styleable name="FontStyle">
<attr name="font_small" format="dimension" />
<attr name="font_medium" format="dimension" />
<attr name="font_large" format="dimension" />
<attr name="font_xlarge" format="dimension" />
</declare-styleable>
Then in values/styles.xml declare few sets of font sizes:
<style name="FontStyle">
</style>
<style name="FontStyle.Small">
<item name="font_small">14sp</item>
<item name="font_medium">16sp</item>
<item name="font_large">18sp</item>
<item name="font_xlarge">20sp</item>
</style>
<style name="FontStyle.Medium">
<item name="font_small">18sp</item>
<item name="font_medium">20sp</item>
<item name="font_large">22sp</item>
<item name="font_xlarge">24sp</item>
</style>
<style name="FontStyle.Large">
<item name="font_small">26sp</item>
<item name="font_medium">28sp</item>
<item name="font_large">30sp</item>
<item name="font_xlarge">32sp</item>
</style>
Then in onCreate()
method of every activity add:
getTheme().applyStyle(new Preferences(this).getFontStyle().getResId(), true);
where Preferences
is a facade to SharedPreferences
object:
public class Preferences {
private final static String FONT_STYLE = "FONT_STYLE";
private final Context context;
public Preferences(Context context) {
this.context = context;
}
protected SharedPreferences open() {
return context.getSharedPreferences("prefs", Context.MODE_PRIVATE);
}
protected Editor edit() {
return open().edit();
}
public FontStyle getFontStyle() {
return FontStyle.valueOf(open().getString(FONT_STYLE,
FontStyle.Medium.name()));
}
public void setFontStyle(FontStyle style) {
edit().putString(FONT_STYLE, style.name()).commit();
}
}
and FontStyle is:
public enum FontStyle {
Small(R.style.FontStyle_Small, "Small"),
Medium(R.style.FontStyle_Medium, "Medium"),
Large(R.style.FontStyle_Large, "Large");
private int resId;
private String title;
public int getResId() {
return resId;
}
public String getTitle() {
return title;
}
FontStyle(int resId, String title) {
this.resId = resId;
this.title = title;
}
}
And FontStyle.values()
is used as items for Spinner
in your PreferencesActivity
.
That's how mine looks like:
public class PreferencesActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
getTheme().applyStyle(new Preferences(this).getFontStyle().getResId(), true);
super.onCreate(savedInstanceState);
setContentView(R.layout.preferences);
Preferences prefs = new Preferences(this);
Spinner fontStylesView = (Spinner) findViewById(R.id.font_styles);
FontStylesAdapter adapter = new FontStylesAdapter(this,
R.layout.font_styles_row, FontStyle.values());
fontStylesView.setAdapter(adapter);
fontStylesView.setSelection(prefs.getFontStyle().ordinal());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.preferences, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_done:
onMenuDone();
finish();
return true;
case R.id.menu_cancel:
finish();
return true;
default:
return false;
}
}
private void onMenuDone() {
Preferences prefs = new Preferences(this);
Spinner fontStylesView = (Spinner) findViewById(R.id.font_styles);
prefs.setFontStyle((FontStyle) fontStylesView.getSelectedItem());
}
}
And finally you can use your font size preferences:
<TextView android:textSize="?attr/font_large" />
Or I prefer using styles, in values/styles.xml add:
<style name="Label" parent="@android:style/Widget.TextView">
<item name="android:textSize">?attr/font_medium</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="Label.XLarge">
<item name="android:textSize">?attr/font_xlarge</item>
</style>
And you can use it in this way:
<TextView style="@style/Label.XLarge" />
I hope my answer will help you.