📜 ⬆️ ⬇️

How to separate the topic from the application

The problem of customization (customization) of the appearance of Android applications often arises before developers. The reason may be the need to follow the interface to the corporate style or the requirement of the customer who wants his application to look special, and not just as a set of standard elements.

There are tools built into the platform for these purposes (themes, styles), but they do not provide a clear mechanism for changing the application interface without changing the code of the application itself.

I propose a technology that allows you to dynamically change the appearance of an Android application by installing new “themes” that can be downloaded separately from the application. The development described in the article was carried out as a pilot project in the mobile application department of Mera-NN ( www.meranetworks.com ), where the author works.

Library


The considered mechanism provides for the distribution of themes as separate .apk files that can be downloaded from the developer’s website and installed on the device as a regular Android application. It is possible to change themes for both basic platform elements and newly created (custom) UI elements.
')
The idea is based on the fact that the Android API allows you to access resources from another application from one application.

Sample code for accessing resources from another application:

PackageManager pm = context.getPackageManager(); Resources res = pm.getResourcesForApplication ("package name"); Resources.Theme rstheme = res.newTheme(); 

here package name is an arbitrary package installed on the device.

The change of the theme for a separate activity can be made only immediately before its creation. In order not to do this each time I created the BaseActivity class in which the onCreate () method was overridden. Also, if we are going to use the resources of another application, it is necessary to override the methods that are used to gain access to resources and topics from these resources.

The source code for the BaseActivity class is shown below.

 package com.mera.detachedthemeslib; import android.app.Activity; import android.content.res.Resources; import android.os.Bundle; public abstract class BaseActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ActivityManager.setThemeForActivity(this); super.onCreate(savedInstanceState); } @Override public Resources getResources() { return ActivityManager.getResourcesForActivity(this, super.getResources()); } @Override public Resources.Theme getTheme() { return ActivityManager.getThemeForActivity(this, super.getTheme()); } } 

In order to manage the current configuration of the application, the ThemeManager class was created.
It implements the following functionality:

 static List<Theme> getThemes(Context ctx, ThemesConfiguration cfg) 


 static void setTheme(Context ctx, Theme theme) 

An example of using ThemeManager will be shown below in the sample code for the application using the separated themes.

These classes (BaseActivity and ThemeManager), as well as a set of auxiliary classes, were combined into a library that is available on github .

Developing applications using the library:


In order to be able to dynamically switch topics in the application, certain conditions must be met.

First, in order for the application being developed to allow dynamic change of topics, it is necessary that all the Activities of this application be inherited from BaseActivity (BaseListActivity, BasePreferenceActivity).

Secondly, the application must contain a theme named "MainTheme".
An example from the developed application:

 <style name="MainTheme" parent="android:Theme"> <item name="custButtonStyle">@android:style/Widget.Button</item> </style> 

If there are other standard themes embedded in the application, and if necessary, to make them available to users, they should be indicated when accessing ThemeManager. An example of how this is done is given below when adding the “Green” theme.

There are also restrictions for an additional application providing a separate topic:

Below is a sample code for the application using the separate topics:

Main application screen:

 package com.mera.detachedthemesapp; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Spinner; import com.mera.detachedthemeslib.BaseActivity; public class MainActivity extends BaseActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String[] items = new String[] {"One", "Two", "Three"}; Spinner spinner = (Spinner) findViewById(R.id.spinner1); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, items); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); this.findViewById(R.id.switch_button).setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { startActivity(new Intent(MainActivity.this, SwitchThemeActivity.class)); } }); } } 

A screen with a list of topics for switching between them:

 package com.mera.detachedthemesapp; import java.util.List; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.TextView; import com.mera.detachedthemeslib.BaseListActivity; import com.mera.detachedthemeslib.ThemesConfiguration; import com.mera.detachedthemeslib.ThemeManager; public class SwitchThemeActivity extends BaseListActivity { private LayoutInflater mInflater; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); List<ThemeManager.Theme> themes = ThemeManager.getThemes(this, new ThemesConfiguration() .addInnerTheme(R.style.CustomTheme2, "Green")); ArrayAdapter<ThemeManager.Theme> adapter = new ArrayAdapter<ThemeManager.Theme>( this, android.R.layout.simple_list_item_1, themes) { @Override public View getView(int position, View convertView, ViewGroup parent) { View row; if (null == convertView) { row = mInflater.inflate( android.R.layout.simple_list_item_1, null); } else { row = convertView; } TextView tv = (TextView) row.findViewById(android.R.id.text1); tv.setText(((ThemeManager.Theme) getItem(position)).mTitle); return row; } }; getListView().setAdapter(adapter); getListView().setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ThemeManager.Theme theme = (ThemeManager.Theme) getListView() .getAdapter().getItem(position); ThemeManager.setTheme(SwitchThemeActivity.this, theme); Intent intent = new Intent(); intent.setClass(SwitchThemeActivity.this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); SwitchThemeActivity.this.startActivity(intent); } }); } } 

What it looks like ...


The developed application allows you to change the appearance of the application using two built-in themes.

Also, the application allows you to install and use a new theme that was downloaded and installed separately as a regular Android application.

The code for the library and sample application with a separate topic is available on github .
DetachedThemesLib - library
DetachedThemesApp - application
DetachedThemesTheme - a separate topic

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


All Articles