这一篇博文的思路很简单,没有什么深入的理论,源由是最近在实习公司里开发用到了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里进行定义即可,具体看其他教程。这里获得用户传入的资源文件:
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 l表示想要设置view的宽度,s表示想要设置View的高度,w即为图片宽度,h图片高度rX 水平方向的偏移量,rY垂直方向偏移量。r为宽高比。nh图片切割后的高度,nw图片切割后的宽度。 同理,还有一种情况是,当w除以比率得到的新高超出图片高度时,即得换得高度去乘以比率来获得新的宽度。分析图如下: 好的,整个分析就这样,代码如下: 小图: 大图: 高>宽: 宽>高: 好了,一个自定义的通知,以及一个自定义的田字格显示图片的View制作而成,当然后期可以再拓展开发,如QQ的九宫格显示等等。 这个通知也好,控件也罢,都挺简单的,但是真正去写它,还是花了一些时间,特别是在处理图片这一块。另外,我现在有了一个小小的心得,遇到问题,不要一味地去依赖网上的答案,静下心来想一想,其实自己的解决方案说不定更赞。 加油,共勉。
测试控件的适配性能,原图两张长>宽,两张宽>长:
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;
}