July 6, 2016 update: Theme Gallery sub-project address: themeskinning, make it easier to integrate your app. Welcome to star and use to provide improvement advice.
Update log:
v1.3.0: Add one-click Toggle Font (First edition)
v1.2.1: Perfecting the creation of previous versions of view
v1.2.0: Increase skin Properties Custom extension
v1.1.0: Can directly load skin files on the network
Today we will bring you a dry article. Android Theme skin, can be plug-in to provide skins package, without the activity of the restart directly to achieve seamless switch, can be high imitation netease cloud music theme skin.
This link is the demo package out of the sample Skinchangedemo, you can go to download the first try the effect, skin files to be placed in the root directory of the memory card.
About the theme of Android skin is a commonplace problem. Online gives the program is endless, recently I also want to know this aspect of knowledge, so I go to search will have a lot of articles on this aspect, but the final results are unsatisfactory, and some really give some better solution, but not a substantive demo can be consulted, So it can only be an armchair, and some, indeed, is given a reference to the demo but the final result is not what I want. This article is a summary of the Android skin rejuvenation technique, which is a valuable reference to the Android skinning technology. Interested students can go to understand, as is a knowledge of the popularization.
One of the skin-changing options I'm going to implement today is based on the open source framework android-skin-loader on GitHub. The mechanism of this framework is the use of dynamic loading mechanism to load the contents of the skin pack, without acitvity restart to achieve real-time skin replacement, skin pack can be separated from the original installation package, you need to customize (this skin pack is actually an ordinary Android project, Only the resource file does not have a class file only), the advantage is that you can provide skin package online for users to download, but also greatly reduce the volume of installation package, but also a good implementation of the plug-in. in fact, this framework can be used directly to use, directly a few lines of code can basically solve the theme of Android skin, but as a programmer how can just simply know how to use it? If that's true, it's too low. Meet a good open source project at least we need to take a look at his source code, walk the basic process, understand his basic principles, so that we can be technically improved. The demo implemented in this article is based on the demo improvements in the use of the Android Material Design compatibility library that I released earlier in the paper. The final app is also a materialdesign design style.
Well said so much, through this article you can learn what, this may be a little bit of concern for everyone
- Design an app based on the materialdesign style
- Self-realization of a theme skin-changing framework
- High imitation NetEase cloud music theme Skin (PS: Actually I would like to use this as the title, this can also increase the flow, but I do not want to simply do a title party, to bring you dry is the most important)
- Make your technology A higher level (this is said to be white)
Said so long may be someone can not restrain: I came to see dry goods, not to hear you blind BB. Don't rush the dry goods at once. If you really feel bored can jump directly to the end of the text to see the source code. Let's have a few for a second.
NetEase cloud Music Skin Changing interface
This is NetEase cloud music's skin-changing interface, he provides a few default, but also provides a theme that can be downloaded online, his switching effect is very good, the students who used this software is sure to know. After studying this article, you can make a similar effect to this skin change.
Demo final
This dynamic graph is the final result of our demo implementation, this demo is still relatively simple in general, only provides three kinds of skin. Achieve a basic skin-changing effect, mainly used to learn to use. Of course, more complex skin-changing based on the demo is also possible, here is mainly to explain the principle.
Before the introduction also need to give you a layoutinflaterfactory related knowledge. If you already know the point of this knowledge, the following paragraph can be directly skipped.
For layoutinflater everyone may be unfamiliar, when you need to convert the XML file into a corresponding view must use it, I think he how to use it is not I introduced. Layoutinflater provides setfactory (Layoutinflater.factory Factory) and SetFactory2 (Layoutinflater.factory2 Factory) Two ways you can customize the fill of the layout (a bit like a filter, we can do some extra things before populating the view, but not exactly), Factory2 is added in API 11.
They provide the following method for you to rewrite. In this case you can define yourself to create the view you want, and if you return null in the overridden method, you will create the view in the default way.
View Oncreateview (String name, context context, AttributeSet attrs)//layoutinflater.factory
View Oncreateview (view parent, String name, context context, AttributeSet attrs)//layoutinflater.factory2
Layoutinflater have been set up a default factory,activity is implemented Layoutinflater.factory interface, So you can customize the view's fill by rewriting oncreateview directly in your activity.
The following sentence is a better understanding of layoutinflater.factory
Inflating your own custom views, instead of letting the system does it
This is one of the more important technical points of this demo. If you want to know more about the end of the article will have a reference link.
Let's start by introducing how to do this theme-changing skin.
Let's take a look at this demo project structure:
Project Structure diagram
As for the Xrecyclerview can not do, here we do not use (this is not used, and this is irrelevant), he is just a recyclerview an extension framework, support pull-down and pull-up loading, is a on GitHub on an open source project.
Here we take a direct look at Lib_skinloader this library (the content is mostly derived from the framework of Android-skin-loader, I only made a partial modification, mainly adapted to Appcompatactivity, The original framework was developed based on the original activty, and here again thanks to the open source author, this library is the core of what we are talking about today.
Lib_skinloader Package Structure diagram
We all know that in Android, if you want to get a resource file, you have to get it through resources. The core idea of this library is to dynamically load the packages in the third-party package, acquire the resources and acquire the resource to obtain the contents of the third-party package, and finally set it to the view that we need to respond to the skin changes.
Here I'll just cover load and base two packages, and the contents of the other packages will be covered when explained
1.load Pack
Let's take a look at the contents of this load package (this is actually the core of today's core content).
Load Package
There are two classes of files: Skininflaterfactory, Skinmanager
Let's take a look at the implementation of Skinmanager and jump directly to the Load method
public void Load (String skinpackagepath, Final Iloaderlistener callback) {
New asynctask<string, Void, resources> () {
protected void OnPreExecute () {
if (callback! = null) {
Callback.onstart ();
}
}
@Override
Protected Resources doinbackground (String ... params) {
try {
if (params.length = = 1) {
String Skinpkgpath = params[0];
LOG.I ("Loadskin", Skinpkgpath);
File File = new file (Skinpkgpath);
if (file = = NULL | |!file.exists ()) {
return null;
}
Packagemanager mPm = Context.getpackagemanager ();
PackageInfo mInfo = Mpm.getpackagearchiveinfo (Skinpkgpath, packagemanager.get_activities);
Skinpackagename = Minfo.packagename;
Assetmanager Assetmanager = AssetManager.class.newInstance ();
Method Addassetpath = Assetmanager.getclass (). GetMethod ("Addassetpath", String.class);
Addassetpath.invoke (Assetmanager, Skinpkgpath);
Resources superres = Context.getresources ();
Resources Skinresource = new resources (Assetmanager, Superres.getdisplaymetrics (), superres.getconfiguration ());
Skinconfig.saveskinpath (context, Skinpkgpath);
Skinpath = Skinpkgpath;
Isdefaultskin = false;
return skinresource;
}
return null;
} catch (Exception e) {
E.printstacktrace ();
return null;
}
}
protected void OnPostExecute (Resources result) {
Mresources = result;
if (mresources! = null) {
if (callback! = null) callback.onsuccess ();
Notifyskinupdate ();
} else {
Isdefaultskin = true;
if (callback! = null) callback.onfailed ();
}
}
}.execute (Skinpackagepath);
}
This method has two parameters, the first one is the path of the skin package, and the second one is a simple callback
One of the doinbackground methods to achieve dynamic to obtain the skin package of resources, when successful, in the OnPostExecute method will be assigned to the resources of our defined variables, in order to facilitate the use of our later, Notice that when the resources obtained are not empty, that is, we have acquired the resource inside the skin pack, we call Notifyskinupdate () to notify the interface to change the skin, or use the default skin if it is empty.
Let's take a look at the implementation of Notifyskinupdate ()
Notifyskinupdate
Here is a simple way to go through the Mskinobservers collection and then go to notify the update. For Iskinupdate is an interface, every activity that needs skin updates needs to implement this interface.
Skinmanager This class also has a method such as GetColor (int resId), getdrawable (int resId), is to get a third-party package corresponding to the resource file, it is worth noting that if your third party package does not have a corresponding resource file, Then the default resource file will be used, and if you have a requirement, you can simply add some methods like Getmipmap (int resID).
Yes, there's one more important way to forget about it.
Restoredefaulttheme
This approach is to revert to the system's default theme, the principle and load are similar, the implementation is much simpler. Skinmanager This class to say so much, detailed implementation please go to the source code to see, many places I have given comments.
Let's take a look at Skininflaterfactory, where the main thing is to do some of the fill view related work. I realized that layoutinflaterfactory this interface rather than the article mentioned before the Layoutinflater.factory this interface is because it needs to be compatible with appcompatactivity, if you still use the previous one there will be some errors, anyway, I just got The waiting is a long time to toss. Regardless of how the principle is always the same. Skininflaterfactory's role is to collect the view that needs to respond to changes in the skin.
Let's take a look at the implementation of Oncreateview
Oncreateview
First of all, let's see if there is a need for the current view to change the skin, and if not we will return to the default implementation. If there is, we'll handle it ourselves.
Look at the implementation of the CreateView method
CreateView
Looks a lot, in fact this method is to dynamic to create a view.
Let's look at the implementation of Parseskinattr:
Parseskinattr
This method is actually to collect the changes in the view of the properties can be changed when we change the skin is to change the values of these properties, here you have to note that the value of this property must be reference type (for example: @color/red), must not write dead, The second if's judgment is the function. you may have a question here, how do I know which properties need to be changed when the skin is changed? If you're careful, you'll notice this line of code.
Skinattr mskinattr = Attrfactory.get (attrname, id, entryName, typeName);
Here's a attrfacory. His role is to create skinattr dynamically, based on the attribute name. Some constants similar to these are defined in Attrfacory:
This is the properties that we can change when we change the skin. Skinattr is an abstract class, such as background to create a backgroundattr, the properties used in this project are all in the attr package. Skinattr is a relatively flexible place, and if you have a property that needs to be changed at the time of skin change, you can implement a corresponding skinattr.
At the end of this method we parseskinattr the view and the skinattr into a skinitem and then add it to a collection, and finally note that if the current skin is not the default skin, be sure to apply it. The main thing to do is to prevent the skin from changing to start some new pages that may cause a problem with a change in time. Skininflaterfactory This class also provides a dynamic method of adding skinitem, the principle is similar to here, I do not too much to say.
Load package inside of these two classes speak almost, here to understand the back of the content is a piece of cake, I believe you looked here to see the source code will be more easily.
2.base Pack
Base Package Structure
Can see this package is definitely activity, Fragment, application implementation, the role is bound to encapsulate some common methods and properties inside.
Let's analyze it one by one.
- Skinbaseapplication:
Skinbaseapplication
As you can see here we have done some initialization operations on Skinmanager. In the future, we need the skin to change the needs of the application must remember must inherit from Skinbaseapplication.
- Skinbaseactivity
Let's take a look at the OnCreate method.
Skinbaseactivity
Here we use the inflaterfactory of our previously customized view to replace the default factory. Remember to be sure to Super.oncreate (savedinstancestate) Before this method is called. Skinbaseactivity also provides a way to dynamically add a view that responds to your skin's changing needs. Of course the activity that needs to respond to the change of skin needs to inherit skinbaseactivity. Detailed implementation please see the source code.
- Skinbasefragment
This is the same idea as skinbaseactivity. Concrete implementation look at the source, here I just give you the idea of the skin-changing framework, so that everyone in the source of the time to look more relaxed.
This framework is introduced here, let's see how to use it.
In the use of the time must remember to the activity to inherit from the skinbaseactivity,fragment to inherit from the skinbasefragment,application to inherit from Skinbaseapplication. Of course, making this framework a dependency on your project is definitely essential. For the simple demo, here I only use the following three colors as a resource to change the skin, of course, if you want to use the Drawable file can also be done, if you must be able to read this demo.
Look at a layout file
which
xmlns:skin="http://schemas.android.com/android/skin"
Is our custom, in Skinconfig has.
We just need to add skin:enable= "true" to the view that has the skin change requirement.
And take a look at some of Mainacticvity's code.
This is the dynamic addition of a view that has skin change requirements.
The above describes the use of methods in layout files and the use of methods in code.
How are we supposed to change the skin? Very simple, just call the Skinmanager load method can be, the skin path into it, my demo for the sake of simplicity, did not do on-line skin-changing function, just in the local to provide a replacement of the skins, see here I believe you on how to change skin online already have an idea.
How to change skin
Finally, let's look at how to develop a skin pack. In fact, this is the simplest, skin pack is actually a basic Android project, which contains no class files, only resource files. just note here the resource file name must be the same as in the original project, and only with those that need to change when the skin changes! For example, my demo is simply a simple switch to the three colors above. Developed the brown and black two skins, so there are only three color values in the resource file, we need to package it as an APK file after development, to prevent the user from clicking on the installation, we have changed the suffix to skin, which is also marked. If still not very clear can go directly to the source view.
Let's take a look at the beginning of the article is not suddenly become a train of thought, quickly move your little finger to hit a theme skin changing frame Bar ~ ~ ~
Demo final
Okay, here's the end of this article. Thank you very much for your patience to read!
SOURCE transfer: Materialdesigndemo welcome All Star and Fork,bug must be inevitable, there are a lot of discussion.
Reference Links:
- Layoutinflater factories (ladder required)
- How to Get the right Layoutinflater
- Research on dynamic loading mechanism of Android apk
- Overview of Android Skin-changing technology
Wen/_solid (author of Jane's book)
Original link: http://www.jianshu.com/p/af7c0585dd5b
Copyright belongs to the author, please contact the author to obtain authorization, and Mark "book author".
Android Theme Change Seamless switch