说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
来源:互联网 发布:tensorflow分布式搭建 编辑:程序博客网 时间:2024/04/29 18:06
上一篇中,我们了解了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_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, "选择壁纸"));
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);
- }
- @Override
- public 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();
- }
- }
- }
- }
/** * * 当别的应用程序改变了壁纸后,这里定义一个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);
- }
- }
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();
- }
/** * 这里加载壁纸,需要重新绘制界面 * @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();
- }
/** * 壁纸本身可能并没有整个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);
//加载壁纸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的拖拽之谜...
- 说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
- 说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
- 说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
- 说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
- 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加
- 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加
- 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加
- 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加
- 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加
- 说说Android桌面(Launcher应用)背后的故事(九)——让我的桌面多姿多彩
- 说说Android桌面(Launcher应用)背后的故事(九)——让我的桌面多姿多彩
- 说说Android桌面(Launcher应用)背后的故事(九)——让我的桌面多姿多彩
- 说说Android桌面(Launcher应用)背后的故事1
- 说说Android桌面(Launcher应用)背后的故事2
- 说说Android桌面(Launcher应用)背后的故事(一)——揭开她神秘的面纱
- 说说Android桌面(Launcher应用)背后的故事(三)——CellLayout的秘密
- 说说Android桌面(Launcher应用)背后的故事(一)——揭开她神秘的面纱
- 说说Android桌面(Launcher应用)背后的故事(一)——揭开她神秘的面纱
- Aaron Swartz:如何提高效率
- 马云回忆与乔布斯的见面 论创新之必要条件
- oracle常见错误代码说明备忘
- Ubutn操作系统学习笔记三之------文件系统基本结构
- 两个线程A和B,任务都是打印当前时间,要求编码实现:线程A和B同时启动后,以先A后B的方式任务交叉执行10次。
- 说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
- 大数据实战
- C++小结(一)—基本了解
- 说说Android桌面(Launcher应用)背后的故事(六)——研究Launcher而实现的附属品(可以拖拽的ListView)
- 哈尔滨理工大学第四届ACM程序设计竞赛J: xiaodao 我爱你!
- 说说Android桌面(Launcher应用)背后的故事(七)——又是一个附属品(可以转动的绚烂饼图)
- 项目管理---敏捷开发思想---带来相当愉快的项目开发过程
- 【FJOI2014】石子合并问题
- Java JDBC 连接Oracle