说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加

news/2025/1/1 23:56:03/

 

 

上一篇中,我们了解了Workspace是如何处理多个CellLayout之间的滑动的。这篇,将记录如何将壁纸添加到桌面,以及Workspace如何处理滑动的时候,壁纸的滑动。

壁纸的添加,也是调用系统自带的,用如下方式调用:

	//调用系统自带壁纸选择功能,ACTION_SET_WALLPAPER为选择的时候使用的过滤条件Intent chooseIntent = new Intent(Intent.ACTION_SET_WALLPAPER);//启动系统选择应用Intent intent = new Intent(Intent.ACTION_CHOOSER);intent.putExtra(Intent.EXTRA_INTENT, chooseIntent);intent.putExtra(Intent.EXTRA_TITLE, "选择壁纸");startActivity(intent);

这样就会列出所有Action含有android.intent.action.SET_WALLPAPER的应用。当然,上面的代码也可以直接简写为:

  Intent chooseIntent = new Intent(Intent.ACTION_SET_WALLPAPER);startActivity(Intent.createChooser(chooseIntent, "选择壁纸"));

 

但是,按照常见的,应该是startActivityForResult来启动,然后在onActivityResult中来获取返回后的壁纸。但是,选择壁纸后,并不是通过这种方式获取选择的壁纸的,那么我们如何获取选择的壁纸呢?

其实,当我们选择了一张壁纸后,系统会发出一个Broadcast,同时将选择的壁纸,缓存在整个应用程序的上下文中,这样,其实就是由于壁纸,不仅可以在桌面上更换,也可以在图片显示应用中更换,所以,其使用Broadcast机制来通知壁纸已经更换。我们需要实现一个BroadcastReciever来监听壁纸的选择:

    /*** * 当别的应用程序改变了壁纸后,这里定义一个BroadcastReceiver来接受通知**/class WallpaperIntentReceiver extends BroadcastReceiver{private Application application;//WeakReference使得WallpaperIntentReceiver不会因为Launcher的引用而被推迟注销掉private WeakReference<UorderLauncher> rLauncher;public WallpaperIntentReceiver(Application application, UorderLauncher launcher) {this.application = application;this.rLauncher = new WeakReference<UorderLauncher>(launcher);}public void setLauncher(UorderLauncher l){this.rLauncher = new WeakReference<UorderLauncher>(l);}@Overridepublic void onReceive(Context context, Intent intent) {Log.v(TAG, "更换了壁纸");/*** 从ApplicationContext获取壁纸*/final Drawable lDrawable = application.getWallpaper();if(lDrawable instanceof BitmapDrawable){Log.v(TAG, "壁纸是BitmapDrawable类型的");mWallpaper = ((BitmapDrawable)lDrawable).getBitmap();}else{throw new IllegalStateException("The wallpaper must be a BitmapDrawable object");}/*** 如果此时Launcher是活动的,未被锁定,则加载新的Wallpaper*/if(rLauncher != null){final UorderLauncher launcher = rLauncher.get();if(launcher != null){launcher.loadWallpaper();}}}}


在这个BroadcastReciever中,直接通过Application.getWallpaper();获取最新的壁纸,那么有了BroadcastReciever,我们怎么知道这个Reciever是接收壁纸更换的Broadcast的呢?所以,我们需要注册它:

	private void registerIntentReceivers(){if(mWallpaperReceiver == null){mWallpaperReceiver = new WallpaperIntentReceiver(getApplication(), this);/*** 注册的时候,指定IntentFilter,这样改BroadcastReciver就是接收壁纸更换的Broadcast的了*/IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);getApplication().registerReceiver(mWallpaperReceiver, filter);}else{mWallpaperReceiver.setLauncher(this);}}


现在,知道了壁纸的获取,那么,接下来我们自然而然想到的是:壁纸我已经获取到了,但是怎么样将它绘制在Workspace上面呢?注意,上面BroadcastReceiver获取到壁纸的时候调用了launcher.loadWallpaper()来完成壁纸加载的,在这个方法中,可以看到其调用了mWorkspace.loadWallpaper(mWallpaper);那么,就需要回到Workspace中了:

	/*** 这里加载壁纸,需要重新绘制界面* @param wallpaper*/public void loadWallpaper(Bitmap wallpaper) {wallpaperLoaded = true;mWallpaper = wallpaper;//要求重新绘制界面requestLayout();invalidate();}


这个方法仅仅要求重新绘制布局,那么,我们就知道,在绘制的方法中,应该会对壁纸进行相关的绘制。在dispatchDraw中,有对壁纸的处理,

    	/*** 壁纸本身可能并没有整个workspace那么宽* 所以,屏幕滑动的时候,壁纸向右边滑动的距离需要根据mWallpaperOffset做相应的调整*/float x = getScrollX()*mWallpaperOffset;//这里啥个意思,TODO:Log.v(TAG, "getRight-getLeft="+getRight()+"-"+getLeft()+"="+(getRight()-getLeft()));/*** getRight()-getLeft()=手机屏幕的宽度*/if(x<getRight()-getLeft()-mWallpaperWidth){//当壁纸宽度小于屏幕宽度的时候,才会出现小于的情况//这种情况就固定//但是在获得用户选择的壁纸的时候,我们对其作了大小调整,所以,这里基本不会出现这种情况x = getRight()-getLeft()-mWallpaperWidth;}float y = (getBottom()-getTop()-mWallpaperHeight)/2;Log.v(TAG, "开始画壁纸:x,y分别为:"+x+","+y);//canvas.drawColor(Color.BLACK);if(mWallpaper!=null){Log.v(TAG, "开始画壁纸");canvas.drawBitmap(mWallpaper, x, y, mPaint);//invalidate();} 


在这里,我们看到了,其通过canvas.drawBitmap(mWallpaper, x, y, mPaint);绘制了壁纸,这里关键的是x,y的计算,桌面可以横向滑动的,那么每次滑动后重新绘制的时候,这个x的值是在变化的,通过代码我们可以发现,其中有一个变量mWallpaperOffset,查找这个变量,在onMeasure中,对该变量进行了赋值:

		//加载壁纸if(wallpaperLoaded){wallpaperLoaded = false;mWallpaper = BitmapUtils.centerToFit(mWallpaper, width, height, getContext());mWallpaperWidth = mWallpaper.getWidth();mWallpaperHeight = mWallpaper.getHeight();Log.v(TAG, "测量壁纸大小:"+mWallpaperWidth+","+mWallpaperHeight);}final int wallpaperWidth = mWallpaperWidth;//计算Wallpaper每次随着屏幕滑动移动的距离if(wallpaperWidth > width){/*** 计算壁纸滑动的速率* 壁纸可以滑动的距离是count*width-wallpaperWidth* 屏幕可以滑动的距离是(count-1)*width* 这样,一除就是壁纸相对于屏幕滑动的速率了*///mWallpaperOffset = wallpaperWidth/(count*(float)width);mWallpaperOffset = (count*width-wallpaperWidth)/((count-1)*(float)width);}else {mWallpaperOffset = 1.0f;}Log.v(TAG, "wallpaper的offset:"+mWallpaperOffset);


这样,当我们每次滑动的时候,Workspace在重绘的时候就会计算这个值,然后在dispatchDraw中首先绘制壁纸,然后绘制每个CellLayout。

好了,至此,我们应该清楚壁纸的添加机制了。

下一篇将揭晓item的拖拽之谜...


http://www.ppmy.cn/news/304544.html

相关文章

分享35套极其精美的高清桌面壁纸免费下载

桌面是人和电脑对话的主要入口,也是人机交互的图形用户界面。壁纸是电脑桌面所使用的背景图片,可以根据大小和分辨率来做相应调整。 壁纸让我们的电脑看起来更好看,更漂亮,更有个性。所以,今天我为大家收集了一批非常精美的高清桌面壁纸,有多种尺寸可以选择,赶紧为你的桌…

酷栈云桌面开启“3+2”混合办公新趋势

近日&#xff0c;携程突然火了&#xff0c;不是因为携程的在线服务平台有啥新的业务&#xff0c;而是因为其宣布的“32”混合办公新模式。 2月14日&#xff0c;在线旅游平台携程集团宣布将在全公司推行“混合办公”&#xff0c;将从3月1日开始推行混合办公制度&#xff0c;每周…

无影云桌面 1块钱体验

这不又到了一年一度购买服务器的时候&#xff0c;各个大厂开始抛出折扣后的服务器&#xff0c;大部分一点折&#xff0c;甚至还有零点几折用来招新。那对于我们老客户改咋办呢… 那当然是找个非计算机专业的朋友借号啦~&#xff08;骚操作&#xff09; 就在我逛阿里云官网的时…

android 锤子桌面壁纸,锤子桌面使用技巧|锤子桌面 1.5.1 安卓版_久友下载站_壁纸美化...

锤子ROM从来都是只闻其声&#xff0c;未见其人。发布会开到现在已经大半年了&#xff0c;却只弄出了这么个玩意来&#xff0c;我对它已无力吐槽&#xff0c;想体验一下的就自己下吧&#xff01; 新版特性&#xff1a; 新增&#xff1a;适配 Smartisan OS 3.0 视觉规范 新增&…

水箱建模最小二乘法_不锈钢水箱特色-不锈钢水箱304价格

水箱分量轻、价格低。特有的板型&#xff0c;高难度的冲压成型工艺以最小资料耗费到高强度要求。 不锈钢保温水箱的参数特色&#xff1a;接头用高频电阻缝焊焊接&#xff0c;确保不易生锈漏水。不锈钢保温水箱采纳SUS304不锈钢板制作&#xff0c;分量轻、造型美观、清洁卫生。5…

winform 判断内外网_静海洗手盆疏通报价–光波网

今日报价:静海洗手盆疏通报价材料去灯配城采购就可以了&#xff0c;如果有条件的的话自己设计图纸去模&#xff0c;这样成本更有优势一些&#xff0c;不过一般量大才这样的。LED节能灯的工艺流程的话难以一点一滴地说清楚了&#xff1a;概括地简说&#xff0c;主要是插件、浸锡…

告诉你压力变送器选型参考大全!

1、变送器要测量什么样的压力 先确定系统中测量压力的最大值&#xff0c;一般而言需要选择一个具有比最大值还要大1.5倍左右的压力量程的变送器。这主要是在许多系统中&#xff0c;尤其是水压测量和加工处理中&#xff0c;有峰值和持续不规则的上下波动&#xff0c;这种瞬间的峰…

石头机器人拖地水量调节_石头扫地机器人 T6 体验:可以自定义清扫区域,拖地功能也更人性化了...

在现代家居生活中,扫地机器人正在被越来越多人所接受。尤其是对于很多忙于工作而没有时间去做家务的年轻人来讲,拥有一台通过远程遥控就能够帮你完成扫地以及拖地任务的扫地机器人,无疑是一件十分幸福的事情。 来自小米生态链企业的石头科技此前已经推出过不少扫地机器人产品…