有趣的手机壁纸——水印壁纸

此应用的代码地址在我的github

此应用已上线,下载地址http://shouji.baidu.com/software/23371524.html


最近看了一个水波纹效果的案例视频,大家可以看看。这个案例实现的效果就是点击或滑动屏幕,在点击和滑动过的地方就会画圆,同时画的圆会慢慢变小,慢慢变淡,直至消失。看着挺好看也挺好玩,然而前一阵子又发布了一个透明壁纸的博客。所以就想能不能把这个水波纹弄到壁纸上,于是这个水印壁纸就诞生了。

因为是新手,所以遇到了很多问题,有些甚至是很基础的问题,但是好在百度了一大堆,基本问题都解决了,总的来说自己的基础还是太差了。

好了看代码,首先要先做壁纸,壁纸的制作可以看我的上一个博客手机透明壁纸,这里就不细说了。

接下来就是在壁纸服务里加入画图的操作。

 Handler mHandler = new Handler();
        // 重复执行的一个方法
        private final Runnable drawTarget = new Runnable() {
            public void run() {
                drawFrame();
            }
        };

这里面定义了一个handler,利用它来重复的调用画图方法,来不断地绘制水印。需要注意的是,在这里绘图我们是直接在surfaceview上进行绘图的,这是另外一个线程,不同于只能在主线程更新UI的那个线程。并且它在底层实现机制中实现了双缓冲机制,所以一般不会阻塞线程。更多的关于surfaceview的知识可以去百度,因为我也是百度的。

接下来就是画图方法了。

private void drawFrame() {
            // 获取该壁纸的SurfaceHolder
            final SurfaceHolder holder = getSurfaceHolder();
            Canvas c = null;
            try {
                // 获取Canvas
                c = holder.lockCanvas();
                if (c != null) {
                    isRuning = true;
                    c.save();
                        Paint paint1 = new Paint();
                    paint1.setAlpha(255);
                    paint1.setAntiAlias(true);
                    paint1.setStyle(Paint.Style.FILL);
                    c.drawBitmap(res,0,0,paint1);
                    // 在触碰点绘制图像
                    drawTouchPoint(c);
                    for (int i = 0; i < wList.size(); i++) {
                        Wave w = wList.get(i);
                        int alpha = w.p.getAlpha();
                        if (alpha == 0) {
                            wList.remove(i);
                            //删除i以后,总数会减少一,否则会漏掉一个对象
                            i--;
                            continue;
                        }
                        alpha -= 10;
                        if (alpha < 10) {
                            alpha = 0;
                        }
                        w.p.setAlpha(alpha);
                    }
                    if (wList.size() == 0) {
                        isRuning = false;
                    }


                }
            } finally {
                if (c != null)
                    holder.unlockCanvasAndPost(c);
            }
            mHandler.removeCallbacks(drawTarget);
            // 调用重绘
            if (mVisible && isRuning) {


                //重复画图
                mHandler.postDelayed(drawTarget,50);
            }
        }

private void drawTouchPoint(Canvas c) {
            for (int i = 0; i < wList.size(); i++) {
                Wave wave = wList.get(i);
                if (waterId == 0) {
                    bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.heart_icon);
                }else{
                    bitmap1 = BitmapFactory.decodeResource(getResources(),waterId);
                }
                c.drawBitmap(bitmap1,wave.cx,wave.cy,wave.p);

            }
        }

绘图的坐标点可以通过onTouchEvent方法获得,点击屏幕画出水印的效果基本完成了,接下来就是遇到的问题了。

首先这样壁纸背景只能是个单色,但是壁纸怎么能这样呢。所以我就又百度了好长时间,最后找出一个方法就是在这个基础上再在画布上画一个图,利用这张图当背景。代码如下

@Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            super.onSurfaceChanged(holder, format, width, height);

            if (path == null){
                bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_back);
            }else {
                bitmap = BitmapFactory.decodeFile(path);
            }

            WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
            int width2 = wm.getDefaultDisplay().getWidth();
            int height2 = wm.getDefaultDisplay().getHeight();
            int width1 = bitmap.getWidth();
            int height1 = bitmap.getHeight();
            Matrix matrix = new Matrix();
            if (width1 >= width2 && height1 >= height2){
                float scaleWight1 = ((float)width2)/width1;
                float scaleHeight1 = ((float)height2)/height1;
                float Scale;
                if (scaleWight1 - scaleHeight1 >= 0){
                    Scale = scaleWight1;
                }else {
                    Scale = scaleHeight1;
                }
                matrix.preScale(Scale,Scale);
                res = Bitmap.createBitmap(bitmap,0,0,width1,height1,matrix,true);
            }
            if (width1 < width2 && height1 < height2){
                float scaleWight = ((float)width2)/width1;
                float scaleHeight = ((float)height2)/height1;
                float Scale2;
                if (scaleWight - scaleHeight >= 0){
                    Scale2 = scaleWight;
                    matrix.preScale(Scale2,Scale2);
                    int y2 = (int)(height1 - height1/Scale2);
                    Bitmap FirstBi = Bitmap.createBitmap(bitmap,0,0,width1,height1,matrix,true);
                    int FirstWid = FirstBi.getWidth();
                    int FirstHei = FirstBi.getHeight();
                    res = Bitmap.createBitmap(FirstBi,0,y2/2,FirstWid,FirstHei-y2/2);
                }else {
                    Scale2 = scaleHeight;
                    matrix.preScale(Scale2,Scale2);
                    int x2 = (int)(width1 - width1/Scale2);
                    Bitmap FirstBit = Bitmap.createBitmap(bitmap,0,0,width1,height1,matrix,true);
                    int FirstWidth = FirstBit.getWidth();
                    int FirstHeight = FirstBit.getHeight();
                    res = Bitmap.createBitmap(FirstBit,x2/2,0,FirstWidth-x2/2,FirstHeight);
                }
            }
            if (width1 >= width2 && height1 < height2){
                float scale3 = ((float)height2)/height1;
                matrix.preScale(scale3,scale3);
                int x3 = (int)(width1 - width1/scale3);
                Bitmap Bitmap3 = Bitmap.createBitmap(bitmap,0,0,width1,height1,matrix,true);
                int FirstWidth3 = Bitmap3.getWidth();
                int FirstHeight3 = Bitmap3.getHeight();
                res = Bitmap.createBitmap(Bitmap3,x3/2,0,FirstWidth3-x3/2,FirstHeight3);
            }
            if (width1 < width2 && height1 >= height2){
                float scale4 = ((float)width2)/width1;
                matrix.preScale(scale4,scale4);
                int y3 = (int)(height1 - height1/scale4);
                Bitmap Bit4 = Bitmap.createBitmap(bitmap,0,0,width1,height1,matrix,true);
                int FirstWidth4 = Bit4.getWidth();
                int FirstHeight4 = Bit4.getHeight();
                res = Bitmap.createBitmap(Bit4,0,y3/2,FirstWidth4,FirstHeight4-y3/2);
            }


            Canvas ca = holder.lockCanvas();
            Paint paint1 = new Paint();
            paint1.setAlpha(255);
            paint1.setAntiAlias(true);
            paint1.setStyle(Paint.Style.FILL);
            ca.drawBitmap(res,0,0,paint1);
            holder.unlockCanvasAndPost(ca);
        }

其实画图的方法还和上面一样,但是又多出了好多判断代码,这就是我遇到的另一个问题。那就是我们可以随便拿一张图片来当壁纸,但是我们的图片尺寸基本和自己的手机屏幕尺寸是不配合的。所以我们就得裁剪图片,使图片适应屏幕。其中matrix.prescale方法只是缩放了图片,但是对于有些图片并不能得到主要的部分,所以我们还要对图片进行偏移。我采用的是先缩放,再偏移的方法也就是上面看到的两次使用createBitmap方法了。代码写的很乱,也懒得改了,因为想这个办法想了好长时间。


最后就是我们要能自己选择手机里的图片作为壁纸,这样可用性会更高。这也就遇到了一个新的问题,那就是如何把我们选择的图片传到我们的壁纸服务中。一开始我就想的是用intent传递数据,这是标准的用法。但是利用启动服务的方法根本传不进去,因为这个壁纸服务根本不是我去启动的,而是手机内部的壁纸管理器去启动的,具体内部的实现我也不知道是怎么回事,所以这个方法就行不通了。后来在看了鸿洋的一个博客,是视频做壁纸的,他上面是用的广播来控制声音开启的。所以我就也仿着去弄,结果是能传递数据进去了,但是只有当壁纸启动起来,才能进行壁纸的更换。具体的情况大家可以试试,这是因为注册的是动态广播只有当服务启动了,才能接收广播。再后来我改了改就直接利用了静态方法来传递数据,以前还真不知道这个方法。不过百度了一下,这个方法好像容易造成传递的数据为空,所以这并不能算最好的方法,还是得慎用。但是我目前还没遇到过为空的时候。

public static void ImagePath(Context context, String data){
        path = data;
    }


最后完整代码我的github

应用已上线,下载地址http://shouji.baidu.com/software/23371524.html







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值