Android O 自定义通知实例及一个自定义自动适配缩放图片至特定大小的田字格ImageView

        这一篇博文的思路很简单,没有什么深入的理论,源由是最近在实习公司里开发用到了Android O的通知,发现与以往有所不同,相关的资料是有,但是大部分都不适用于这个版本,这里只是写一个非常简单的Demo,算是代码的保存吧。另外,为什么一个自定义View要和通知弄一起说呢,是因为本想在这个通知上用上一个自定义的View,结果发现,通知是不支持自定义View 的。

        具体通知的知识点,网上有很多,这里不再缀述。

        Android O的通知与以往最大的不同,在于增加的频道这个概念,所以,在这个版本,倘若,不加入频道,以之前的方式去控制通知,就会弹出以下的错误(弹出一个Toast :Developer warning for package):

                                        没加入频道导致的错误

        所以和以往的最大不同就在此,其他的设置,具体看一下api测试即可。

      说一说自定义通知,自定义通知当然是个创建一个布局文件,然后根据布局文件加载到通知即可。方法是通过创建一个RemoteViews,调用RemoteViews的一系列方法,通过传入View控件的id,及相对应的值,即可完成设置,这个过程也非常简单。代码如下:

               Ps:一定要设置setSmallIcon,否则不能显示。          

         notificationManager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        NotificationChannel mChannel=new NotificationChannel("my_channel_01","123",NotificationManager.IMPORTANCE_LOW);
        mChannel.setDescription("123456");
        mChannel.enableLights(false);

        notificationManager.createNotificationChannel(mChannel);
        builder=new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher);             //一定要设置,不然不能够弹出
        RemoteViews remoteViews=new RemoteViews(getPackageName(),R.layout.notification_layout);
        remoteViews.setTextViewText(R.id.down_tv,"正在下载");
        remoteViews.setProgressBar(R.id.pb,100,50,false);
        builder.setCustomBigContentView(remoteViews);

        btn_notification=(Button)findViewById(R.id.btn_notification);
        btn_notification.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                notificationManager.notify(nofitication_id,builder.build());
            }
        });
        另外,假若你设置了进度条,然后又看不见效果,请注意有没有设置其margin值,有些时候是会被其他的通知给盖住的。至于进度条的样式,可以通过设置其Style或者Theme标签达到想到的效果,如:
style="?android:attr/progressBarStyleHorizontal"

        本来想在通知上加下一个自定义控件,不过一加上去就报了错误,查了一下资料,才得知,原来自定义的通过是加不了自定义控件的。

        这个自定义控件的需求是,传入四张图片,然后可以根据控件的大小去自动调整图片的显示大小,同时对图片的大小进行相对应比例的切割,同时再对图片进行压缩,达到内存调优的效果。

         自定义控件好的教程也是非常多,我这里简单地叙述一下自己的实战经历。

        首先,继承View,然后重写一个含AttributeSet的方法,这个方法似乎是必须,当然这个还要用到自定义属性,方法就是在attrs.xml里进行定义即可,具体看其他教程。这里获得用户传入的资源文件:

 

 <com.example.jakera.notificationtest.FourImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:ImageView1="@mipmap/timg"
        app:ImageView2="@mipmap/timg1"
        app:ImageView3="@mipmap/timg3"
        app:ImageView4="@mipmap/timg4"
        android:background="#269194"/>
      TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.FourImageView);

        imageView1=ta.getResourceId(R.styleable.FourImageView_ImageView1,R.drawable.ic_launcher_background);
        imageView2=ta.getResourceId(R.styleable.FourImageView_ImageView2,R.drawable.ic_launcher_background);
        imageView3=ta.getResourceId(R.styleable.FourImageView_ImageView3,R.drawable.ic_launcher_background);
        imageView4=ta.getResourceId(R.styleable.FourImageView_ImageView4,R.drawable.ic_launcher_background);

         由于onMeasure方法,我们不需要对View的测量作什么处理,这里不重写。

        最重要的当然是onDraw方法,这里我是直接根据用户传入的View大小,计算出每个View的大小,及相对应的间隔。当然,后期应该考虑到可拓展性,应该通过image的个数来计算。

        int viewWidth=(getWidth()/51)*25;
        int viewWidthSpan=getWidth()/51;
        int viewHeight=(getHeight()/51)*25;
        int viewHeightSpan=getHeight()/51;
       根据上边的imageview,及View的大小来进行绘制。Rect封装了View的大小。通过计算能够把四张图张按田字格绘制出来。

     

        Rect mDestRect1=new Rect(0,0,viewWidth,viewHeight);
        canvas.drawBitmap(getBitmap(imageView1,viewHeight,viewWidth),null,mDestRect1,null);


        Rect mDestRect2=new Rect(viewWidth+viewWidthSpan,0,getWidth(),viewHeight);
        canvas.drawBitmap(getBitmap(imageView2,viewHeight,viewWidth),null,mDestRect2,null);


        Rect mDestRect3=new Rect(0,viewHeight+viewHeightSpan,viewWidth,getHeight());
        canvas.drawBitmap(getBitmap(imageView3,viewHeight,viewWidth),null,mDestRect3,null);

        Rect mDestRect4=new Rect(viewWidth+viewWidthSpan,viewHeight+viewHeightSpan,getWidth(),getHeight());
        canvas.drawBitmap(getBitmap(imageView4,viewHeight,viewWidth),null,mDestRect4,null);

        上边的代码调用一个方法,这个方法是作用是,由于我们传入的图片形状不一,假若不进行处理,会出现一个问题,就是图片会在某个方向上被拉伸,显得特别不友好。另一个问题是,我们要把图片放到一个小小的View里边,应该做一下压缩处理,不用把大图加载到内存去。

         一开始图方便,在网上找了许多的代码段,发现很多代码都不适用,有些可以用,但是可能在某些情况下,还是存在拉伸问题,比如当View的宽>长时,可以使用,但是反过来长>宽时不行,捣鼓了大半天,还是没能弄好,索性自己耐下心下来做分析计算,结果还花不了半个小时就完成了。其实也简单,就是一些简单的数学计算。

         思路,首先,根据View要显示图片大小的比例,去切割自己的图片,切割自己的图片要求:按比例切,然后把这个最大的切割区域移动图片中心,即得到图片的中心位置。

       下图为当W/r<h的情况,即切割不会超出图片边界,则宽度保持不变,而高度截出nh的高度,居中也很简单,由于宽度不变,则水平不需偏移,则rX=0;而y的偏移,则为(h-需要截出的高度再除以2)即可。这样便可以截出。

      l表示想要设置view的宽度,s表示想要设置View的高度,w即为图片宽度,h图片高度rX 水平方向的偏移量,rY垂直方向偏移量。r为宽高比。nh图片切割后的高度,nw图片切割后的宽度。

       

       同理,还有一种情况是,当w除以比率得到的新高超出图片高度时,即得换得高度去乘以比率来获得新的宽度。分析图如下:

          好的,整个分析就这样,代码如下:


public Bitmap getBitmap(int path,int height,int width){

        Bitmap srcBitmap=BitmapFactory.decodeResource(getResources(),path);

        int w = srcBitmap.getWidth(); // 得到图片的宽,高
        int h = srcBitmap.getHeight();
        int retX, retY;
        int nw, nh;
            if (w > h * width / height)
            {
                nh = h;
                nw = h * width / height;
                retY = 0;
                retX = (w - nw) / 2;
            } else
            {
                nh = w * height / width;
                nw = w;
                retY = (h - nh) / 2;
                retX = 0;
            }
//在这里切割图片 
 Bitmap bmp = Bitmap.createBitmap(srcBitmap, retX, retY, nw, nh, null,
                false);

        // 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响,我们这里是缩小图片,所以直接设置为false
//这里压缩图片至相应大小。
 Bitmap dst = Bitmap.createScaledBitmap(bmp, width, height, false);
        if (srcBitmap != dst) { // 如果没有缩放,那么不回收
            srcBitmap.recycle(); // 释放Bitmap的native像素数组
        }
        bmp.recycle();     //记得回收
        srcBitmap.recycle();

        return dst;

    }
       测试控件的适配性能,原图两张长>宽,两张宽>长:

       小图:

            

        大图:     


           

        高>宽:

            

        宽>高:

             

        好了,一个自定义的通知,以及一个自定义的田字格显示图片的View制作而成,当然后期可以再拓展开发,如QQ的九宫格显示等等。

        这个通知也好,控件也罢,都挺简单的,但是真正去写它,还是花了一些时间,特别是在处理图片这一块。另外,我现在有了一个小小的心得,遇到问题,不要一味地去依赖网上的答案,静下心来想一想,其实自己的解决方案说不定更赞。

          加油,共勉。

猜你喜欢

转载自blog.csdn.net/jakera/article/details/79089136