市面上對數的App都提供換膚功能,這裡暫且不講白天和夜間模式
下圖是網易雲音樂的換膚功能
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
經典
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
黑
換膚其實就是替換資源(文字、顔色、圖檔等)
一、換膚模式:
1.内置換膚
在Apk包中存在多種資源(圖檔、顔色值)用于換膚時候切換。
自由度低,apk檔案大 一般用于沒有其他需求的日間/夜間模式app
2.動态換膚
通過運作時動态加載皮膚包
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
網易雲下載下傳的資源包
二、換膚流程
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
流程
2.1 采集
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
采集
2.2 如何采集
怎麼才能拿到所有的view這才是關鍵!那麼我們隻能從setContentView()入手
那麼問題來了setContentView()到底幹了什麼
檢視源碼發現setContentView()通過LayoutInflater将xml轉換成View加載到window中
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
源碼三連
inflate幹了什麼?
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
幹貨來了!!!!
LayoutInflate 的核心是createViewFromTag()
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
boolean ignoreThemeAttr) {
...............
View view;
if (mFactory2 !=null) {//核心View的建立工廠 是一個接口
view =mFactory2.onCreateView(parent, name, context, attrs);
}else if (mFactory !=null) {
view =mFactory.onCreateView(name, context, attrs);
}else {
view =null;
}
if (view ==null &&mPrivateFactory !=null) {
view =mPrivateFactory.onCreateView(parent, name, context, attrs);
}
if (view ==null) {
final Object lastContext =mConstructorArgs[0];
mConstructorArgs[0] = context;
try {
if (-1 == name.indexOf('.')) {//判斷是否是自定義View
view = onCreateView(parent, name, attrs);
}else {
view = createView(name,null, attrs);
}
}finally {
mConstructorArgs[0] = lastContext;
}
}
return view;
}
通過分析上面代碼可以看出Factory2如果不為空那麼就調用Factory2的方法建立View
否者就使用onCreateView()方法建立View
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
那麼如果我們給定一個Factory那麼我們就可以監視所有的view
View設定資源檔案的流程如圖所示
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
當我們拿到目前View的資源名稱時就會先去插件中的資源檔案裡找。
這就是換膚的原理
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
加載外部Apk資源檔案
拿到資源檔案相信剩下的大家就知道怎麼玩了
代碼已經上傳給 github,歡迎大家一起讨論研究
使用方式
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
初始化
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI4ADOzEjYzITZhljMvwFcvwVbvNmL1h2cuFWaq5yd3d3Lc9CX6MHc0RHaiojIsJye.jpg)
使用
皮膚包就是一個隻有資源檔案的Apk
大家可以看一下我其他文章哦