轻松实现Android更换皮肤(主题) - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

轻松实现Android更换皮肤(主题)

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:62


今朝很多app都具有换肤功能,可以根据用户本身的爱好定制本身的界面,比如新浪微博,网易消息等等。今天这里我就是要介绍一种机制实现app换肤。
我找了几款app换肤的应用,换肤根本都是改换了界面的Icon,背景图片,配风景等等,根本没有碰到改换构造的,其实结垢荷饲可以改换的,然则认为没有须要。所以这篇文┞仿讲解的换肤也是指换icon,背景图片等资本。
经由过程收集搜刮我发明网上上供给了大年夜概这么集中换肤机制:
1、直接将皮肤包放入apk中,这种筹划实现异常简单,然则不敷灵活,并且还将apk搞大年夜了。
2、将皮肤做成一个自力的apk文件,并和项目工程公用一个shareUsedId,并拥有雷同的签名。这种筹划较第一种方檀卷是灵活性比较大年夜,缺点就是须要用户安装,新浪微博今朝应用的就是这种筹划。
我今天要介绍的┞封种筹划和第二种比较类似,然则我的资本包是不要安装的,毕竟用户一般愿意装一些混乱无章的应用。
在进修这篇文┞仿之前最好进修我的前一篇文┞仿《Android资本治理机制分析》,因为皮肤治理其实就是资本的治理。下面开端进修若何换肤吧
1、起首我们须要预备一个皮肤包,这个皮肤包琅绫擎不会包含任何Activity,琅绫擎只有资本文件,这里我为了简单,仅仅参加一个color.xml(其实就相当于Android体系中的framework_res.apk)
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="main_btn_color">#E61ABD</color>
    <color name="main_background">#38F709</color>
    
    <color name="second_btn_color">#000000</color>
    <color name="second_background">#FFFFFF</color>
    
</resources>

2、将该资本打包成apk文件,放入sd卡中(实际项目你可以大年夜我收集下载)
3、将须要换肤的Activity实现ISkinUpdate(这个可以本身随便定义名称)接口
public class MainActivity extends Activity implements ISkinUpdate,OnClickListener
{
	private Button btn_main;
	private View main_view;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	  this.setContentView(R.layout.activity_main);
		
		SkinApplication.getInstance().mActivitys.add(this);
		btn_main=(Button)this.findViewById(R.id.btn_main);
    btn_main.setOnClickListener(this);
		
		main_view=this.findViewById(R.id.main_view);
		
		
		
		
	}
    	
    @Override
    protected void onResume() {
      super.onResume();
      if(SkinPackageManager.getInstance(this).mResources!=null)
      {
        updateTheme();
        Log.d("yzy", "onResume-->updateTheme");
      }
    }

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			//Toast.makeText(this, "change skin", 1000).show();
			File dir=new File(Environment.getExternalStorageDirectory(),"plugins");
			
			File skin=new File(dir,"SkinPlugin.apk");
			if(skin.exists())
			{
				  SkinPackageManager.getInstance(MainActivity.this).loadSkinAsync(skin.getAbsolutePath(), new loadSkinCallBack() {
          @Override
          public void startloadSkin() 
          {
            Log.d("yzy", "startloadSkin");
          }
          
          @Override
          public void loadSkinSuccess() {
            Log.d("yzy", "loadSkinSuccess");
            MainActivity.this.sendBroadcast(new Intent(SkinBroadCastReceiver.SKIN_ACTION));
          }
          
          @Override
          public void loadSkinFail() {
            Log.d("yzy", "loadSkinFail");
          }
        });
			}
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void updateTheme() 
	{
		// TODO Auto-generated method stub
		if(btn_main!=null)
		{
			try {
				Resources mResource=SkinPackageManager.getInstance(this).mResources;
				Log.d("yzy", "start and mResource is null-->"+(mResource==null));
				int id1=mResource.getIdentifier("main_btn_color", "color", "com.skin.plugin");
				btn_main.setBackgroundColor(mResource.getColor(id1));
				int id2=mResource.getIdentifier("main_background", "color","com.skin.plugin");
				main_view.setBackgroundColor(mResource.getColor(id2));
				//img_skin.setImageDrawable(mResource.getDrawable(mResource.getIdentifier("skin", "drawable","com.skin.plugin")));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		SkinApplication.getInstance().mActivitys.remove(this);
		super.onDestroy();
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		if(v.getId()==R.id.btn_main)
		{
			Intent intent=new Intent(this,SecondActivity.class);
			this.startActivity(intent);
		}
	}
}

这段代率攀琅绫擎重要看onOptionsItemSelected,这个办法琅绫擎,经由过程资本apk路径,拿到该资本apk对应Resources对象。我们直接看看SkinPacakgeManager琅绫擎做了什么吧
/**
 * 解析皮肤资本包
 * com.skin.demo.SkinPackageManager
 * @author yuanzeyao <br/>
 * create at 2015年1月3日 下昼3:24:16
 */
public class SkinPackageManager 
{
  private static SkinPackageManager mInstance;
  private Context mContext;
  /**
   * 当缁な源包名
   */
  public String mPackageName;
  
  /**
   * 皮肤资本
   */
  public Resources mResources;
  
  private SkinPackageManager(Context mContext)
  {
    this.mContext=mContext;
  }
  
  public static SkinPackageManager getInstance(Context mContext)
  {
    if(mInstance==null)
    {
      mInstance=new SkinPackageManager(mContext);
    }
    
    return mInstance;
  }
  
  
  /**
   * 异步加载皮肤资本
   * @param dexPath
   *        须要加载的皮肤资本
   * @param callback
   *        回调接口
   */
  public void loadSkinAsync(String dexPath,final loadSkinCallBack callback)
  {
    new AsyncTask<String,Void,Resources>()
    {

      protected void onPreExecute() 
      {
        if(callback!=null)
        {
          callback.startloadSkin();
        }
      };
   
      @Override
      protected Resources doInBackground(String... params) 
      {
        try {
          if(params.length==1)
          {
            String dexPath_tmp=params[0];
            PackageManager mPm=mContext.getPackageManager();
            PackageInfo mInfo=mPm.getPackageArchiveInfo(dexPath_tmp,PackageManager.GET_ACTIVITIES);
            mPackageName=mInfo.packageName;
            
            
            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, dexPath_tmp);
            
            Resources superRes = mContext.getResources();
            Resources skinResource=new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
            SkinConfig.getInstance(mContext).setSkinResourcePath(dexPath_tmp);
            return skinResource;
          }
          return null;
        } catch (Exception e) {
          return null;
        } 
        
      };
      
      protected void onPostExecute(Resources result) 
      {
        mResources=result;
       
        if(callback!=null)
        {
          if(mResources!=null)
          {
            callback.loadSkinSuccess();
          }else
          {
            callback.loadSkinFail();
          }
        }
      };
      
    }.execute(dexPath);
  }
  
  /**
   * 加载资本的回调接口
   * com.skin.demo.loadSkinCallBack
   * @author yuanzeyao <br/>
   * create at 2015年1月4日 下昼1:45:48
   */
  public static interface loadSkinCallBack
  {
    public void startloadSkin();
    
    public void loadSkinSuccess();
    
    public void loadSkinFail();
  }
  
  
 
}
调用loadSkinAsync后,如不雅成功,就会发送一个换肤广播,并将当前皮肤apk的路径保存到sp中,便于下次启动app是直接加载该皮肤资本。
接收换肤广播是在SkinApplication中注册的,当接收到此广播后,随即调用所有已经启动,并且须要换肤的Activity的updateTheme办法,大年夜而实现换肤。
public class SkinApplication extends Application 
{
	private static SkinApplication mInstance=null;
	
	public ArrayList<ISkinUpdate> mActivitys=new ArrayList<ISkinUpdate>();
	
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		mInstance=this;
		String skinPath=SkinConfig.getInstance(this).getSkinResourcePath();
		if(!TextUtils.isEmpty(skinPath))
		{
		  //如不雅已经换皮肤,那么第二次进来时,须要加载该皮肤
		  SkinPackageManager.getInstance(this).loadSkinAsync(skinPath, null);
		}
		
		SkinBroadCastReceiver.registerBroadCastReceiver(this);
	}
	
	public static SkinApplication getInstance()
	{
		return mInstance;
	}
	
	@Override
	public void onTerminate() {
		// TODO Auto-generated method stub
		SkinBroadCastReceiver.unregisterBroadCastReceiver(this);
		super.onTerminate();
	}
	
	public void changeSkin()
	{
		for(ISkinUpdate skin:mActivitys)
		{
			skin.updateTheme();
		}
	}
}

因为这里换肤仅仅是改换icon,配风景之类的,所以比较简单,如不雅要改换构造文件,那就稍微要复杂一些,这里就不再介绍了,有兴趣的可以本身去研究..

相关案例查看更多