安卓开发-查漏补缺-Bitmap和Canvas及映射

听说点赞关注的人,身体健康,万事如意,工作顺利,爱情甜蜜,一夜暴富,升职加薪……最终迎娶白富美!!!

题目:安卓开发-查漏补缺1

内容简介:本文通过阅读CSDN中各位大佬的博客,做笔记加复制粘贴介绍了安卓中的Bitmap和Canvas还有java中的映射相关的一部分知识,使用java代码进行开发和demo的编写,如果有问题的地方请不吝指教,如果对文内内容有不理解的地方,也希望能积极主动的联系博主进行深刻的探讨,以便于更好的让博主记住这篇博文的内容,好让博主在发光发热的道路上越走越远。[手动狗头]🐶努力,奋斗!

标题一:Canvas和Bitmap的理解

首先Canvas和Bitmap都是为了最后能呈现出自己想想中的View而进行的操作。如果把View看作一个成品的化作,Canvas更像是一个画手的角色,而Bitmap则是画作的内容,画手是作为一个中介的地位,例如Canvas就提供了很多drawXXX的方法,更多是一个动作,它承载了画的方法(比如drawLine,drawCircle等),将内容滑倒Bitmap中,所以起始就能看到Canvas的构造函数,就有一个参数是Bitmap,起始可以把他理解成给Bitmap提供一个画手(Canvas),通过Canvas就能画出我们想要的。

To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap),
a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing).

先翻译一下这句话,

想画一些东西的时候。你须要4个主要的组件,一个Bitmap来存储像素,一个Canvas来接收draw的调用(draw的结果是将像素给画到前面所讲的Bitmap中),
一个源,即是你想画的东西(比方矩形,路径。文本,抑或还有一个位图),最后就是一个画笔(描写叙述想画的颜色和风格等)

无意中看到这描写叙述,我对Canvas和Bitmap的理解突然间有种原来就是这么简单的感觉。

要进行画画的操作就需要一个Canvas来绘制,可是每个Canvas都必须由相应的Bitmap来承载内容,沃恩在Canvas上所作的操作终于都是会写道Bitmap中。Canvas 本意是画布的意思,可是在Android中。它就仅仅是一个媒介,能够通过Canvas来调用drawRect,drawCircle等等,可是实际上画的这些东西终于展现的时候,
都是像素。可是仅仅有Bitmap才能保存像素,而Canvas并不行,所以在创建Canvas的时候,就必须传递一个Bitmap,用来承载画的内容。
能够这么理解。如今在我们面前有一张空白的纸(Bitmap),可是我们不能将画笔直接点到上面,我们必须先在这张纸上面放一块画布(Canvas),然后我们在这张画布上
開始点点点…最后。我们就能够看到,我们全部的形为都通过画布作用到纸上了。这时候。那张空白的纸已经是一张画了,而我们掀掉画布,就能够直接将这张画给别人看了。
而此时。Canvas已经没有作用了,它的作用仅仅在于承接我们的画笔操作,然后将所相应位置的像素存储到相应的Bitmap中。

Drawable
而我们常常还会遇到一个Drawable的类,那这个东西又是什么呢,跟Bitmap又有什么关系呢?

A Drawable is a general abstraction for “something that can be drawn.”
Drawable就是能够被画到画布上的对象。

所以,Bitmap是一种Drawable,于是有了BitmapDrawable。颜色是一种Drawable,所以有了ColorDrawable. 形状是一种Drawable。所以有了ShapeDrawable。
个人觉得。它就是一个相似接口之类的东西,而本质上它也是一个抽象类,继承了Drawable,就表明这东东是可绘制的。

Bitmap

一、基本信息

Bitmap位图包括像素以及长、宽、颜色等描述信息。长宽和像素位数是用来描述图片的,可以通过这些信息计算出图片的像素占用内存的大小。

位图可以理解为一个画架,把图放到上面然后可以对图片做一些列的处理。

位图文件图像显示效果好,但是非压缩格式,需要占用较大的存储空间。

1. Config:表示图片像素类型,包括ALPHA_8、RGB_565、ARGB_4444、ARGB_8888 A:透明度;RGB分别是Red、Green、Blue,三种原色

ARGB_8888:四个通道都是8位,每个像素占用4个字节,图片质量是最高的,但是占用的内存也是最大的;

ARGB_4444:四个通道都是4位,每个像素占用2个字节,图片的失真比较严重;

RGB_565:没有A通道,每个像素占用2个字节,图片失真小,但是没有透明度;

ALPHA_8:只有A通道,每个像素占用1个字节大大小,只有透明度,没有颜色值。

使用场景总结:ARGB_4444失真严重,基本不用;ALPHA_8使用场景特殊,比如设置遮盖效果等;不需要设置透明度,RGB_565是个不错的选择;既要设置透明度,对图片质量要求又高,就用ARGB_8888。

2. CompressFormat:Bitmap.CompressFormat.JPEG、Bitmap.CompressFormat.PNG、Bitmap.CompressFormat.WEBP三种压缩格式

JPEG:一种有损压缩(JPEG2000既可以有损也可以无损),“.jpg"或者”.jpeg"; 优点:采用了直接色,有丰富的色彩,适合存储照片和生动图像效果;缺点:有损,不适合用来存储logo、线框类图。

PNG: 一种无损压缩,“.png”; 优点:支持透明、无损,主要用于小图标,透明背景等;缺点:若色彩复杂,则图片生成后文件很大;

无损压缩,相同质量的webp比PNG小大约26%;有损压缩,相同质量的webp比JPEG小25%-34% 支持动图,基本取代gif
https://www.cnblogs.com/winter-is-coming/p/9112192.html 这篇文章对安卓开发中遇到的Bitmap有详细的解释和使用demo,保存下来以备不时之需。

Canvas

  1. 简介
    定义:画布,是一种绘制时的规则
    是安卓平台2D图形绘制的基础

作用:规定绘制内容时的规则 & 内容
记住:绘制内容是根据画布的规定绘制在屏幕上的
理解为:画布只是绘制时的规则,但内容实际上是绘制在屏幕上的

  1. Canvas的本质
    请务必记住:

绘制内容是根据画布(Canvas)的规定绘制在屏幕上的
画布(Canvas)只是绘制时的规则,但内容实际上是绘制在屏幕上的

  • 总结
    绘制内容是根据画布的规定绘制在屏幕上的
  1. 内容实际上是绘制在屏幕上;
  2. 画布,即Canvas,只是规定了绘制内容时的规则;
  3. 内容的位置由坐标决定,而坐标是相对于画布而言的

注:关于对画布的操作(缩放、旋转和错切)原理都是相同的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qlS22FSo-1666078288487)(C:\Users\29933\AppData\Roaming\Typora\typora-user-images\image-20221018113001406.png)]

Canvas具体使用时是在复写的onDraw()里:

@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas); 
// 对Canvas进行一系列设置
//  如画圆、画直线等等
   canvas.drawColor(Color.BLUE); 
    // ...
    }
}

https://carsonho.blog.csdn.net/article/details/60598775这篇文章对Canvas有最详细的解释和操纵demo。

标题二:JAVA中的一部分映射知识

映射是一个存储关键字和值的关联,或者说是“关键字/值”对的对象,即给定一个关键字,可以得到它的值。关键字和值都是对象,关键字必须是唯一的,但是可以存在相同的值。有的映射可以接收null关键字和null值,有的则不能。

可以将Map视为偶对象保存接口。Collection每一次只保存一个对象,而Map保存的是一对对象,而且这一对对象一定是按照“Key = Value”的形式保存,也就是说,可以通过Key找到对应的Value,那么这就好比使用电话本一样:
⑴ Key = 张三,Value = 110;
⑵ Key = 李四,Value = 120;
如果说现在要想找到张三的电话,那么首先应该通过张三这个Key,然后找到其对应的Value——110,如果现在保存的数据之中没有对应的Key,那么就返回null。

下表给出了支持映射的接口:
在这里插入图片描述

一、Map 接口

Map接口映射唯一关键字到值。关键字(key)是以后用于检索值的对象。给定一个关键字和一个值,可以存储这个值到一个Map对象中。当这个值被存储以后,就可以使用它的关键字来检索它。

Map的方法总结在下表中:
在这里插入图片描述

注意事项

(1)当调用的映射中没有项存在时,其中的几种方法会引发一个NoSuchElementException异常。
(2)当对象与映射中的元素不兼容时,则会引发一个ClassCastException异常。
(3)如果试图使用映射不允许使用的null对象,则会引发一个NullPointerException异常。
(4)当试图改变一个不允许修改的映射时,则会引发一个UnsupportedOperationException异常。

映射不是类集,但可以获得映射的类集“视图”。为了实现这种功能,可以使用entrySet( )方法,它返回一个包含了映射中元素的集合(Set)。为了得到关键字的类集“视图”,可以使用keySet( )方法。为了得到值的类集“视图”,可以使用values()方法。类集“视图”是将映射集成到类集框架内的手段。

二、SortedMap 接口

SortedMap接口扩展了Map,它确保了各项按关键字升序排序

由SortedMap说明的方法总结在下表中:
在这里插入图片描述

注意事项

(1)当调用映射中没有的项时,其中的几种方法将引发一个NoSuchElementException异常。
(2)当对象与映射中的元素不兼容时,则会引发一个ClassCastException异常。
(3)当试图使用映射不允许使用的null对象时,则会引发一个nullPointerException异常。

三、Map.Entry 接口

Map.Entry接口使得可以操作映射的输入

如由Map接口说明的entrySet( )方法,调用该方法可返回一个包含映射输入的集合(Set),这些集合元素的每一个都是一个Map.Entry对象。

下表总结了由该接口说明的方法:
在这里插入图片描述

四、映射类

AbstractMap对3个具体的映射实现来说,是一个超类。AbstractMap的另一个子类——WeakHashMap实现一个使用“弱关键字”的映射,它允许映射中的元素,当该映射的关键字不再被使用时,被放入回收站。

1、HashMap 类

HashMap类使用散列表实现Map接口,它是Map接口中最为常用的子类

HashMap允许一些基本操作,如get( )和put( )的运行时间保持恒定,即便对大型的集合也是这样的。下面的构造方法定义为:

(1)HashMap( ) :构造一个默认的散列映射。
(2)HashMap(Map m) :用m的元素初始化散列映射。
(3)HashMap(int capacity) :将散列映射的容量初始化为capacity。
(4)HashMap(int capacity, float fillRatio) :用它的参数同时初始化散列映射的容量和填充比。

填充比(也称为加载容量)

填充比必须介于0.0与1.0之间,它决定在散列集合向上调整大小之前,有多少空间被充满。具体来说,就是当元素的个数大于散列集合容量乘以它的填充比时,散列集合将被扩大。对于没有获得填充比的构造方法,默认为0.75。

HashMap实现Map并扩展AbstractMap。 它本身并没有增加任何新的方法。应该注意的是:散列映射并不保证它的元素的顺序。 因此,元素加入散列映射的顺序并不一定是它们被迭代方法读出的顺序。

package com.xy.test3;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

public class HashMapDemo1 {
	public static void main(String[] args) {
		// 创建HashMap对象
		HashMap<String, Double> hm = new HashMap<String, Double>();
		// 加入元素到HashMap中
		hm.put("John Doe", new Double(3434.34));
		hm.put("Tom Smith", new Double(123.22));
		hm.put("Jane Baker", new Double(1378.00));
		hm.put("Todd Hall", new Double(99.22));
		hm.put("Ralph Smith", new Double(-19.08));
		// 返回包含映射中项的集合
		Set<Entry<String, Double>> set = hm.entrySet();
		// 用Iterator得到HashMap中的内容
		Iterator<Entry<String, Double>> itr = set.iterator();
		// 显示元素
		while(itr.hasNext()) {
			// Map.Entry可以操作映射的输入
			/* 如果用Map来取值,其过程是先从Map中取得关键字之后,
			 * 再返回到Map中取得相对的值
			 * 而用Map.Entry,可以一次性地得到所有Map中的信息
			 */
			Map.Entry<String, Double> me = (Map.Entry<String, Double>)itr.next();
			System.out.println(me.getKey() + " : " + me.getValue());
		}
		System.out.println();
		// 让John Doe中的值增加1000
		double balance = (Double)hm.get("John Doe").doubleValue();
		// 用新值替换掉旧值
		hm.put("John Doe", new Double(balance + 1000));
		System.out.println("John Doe现在的资金: " + hm.get("John Doe"));
	}
}

【结果】
在这里插入图片描述

2、TreeMap 类

TreeMap类是基于红黑树(Red-Black tree)实现Map接口。TreeMap提供了按排序顺序存储关键字/值对的有效手段,同时允许快速检索。应该注意的是,不像散列映射,树映射保证它的元素按照关键字升序排序。

下面的TreeMap构造方法定义为:

(1)TreeMap( ) :构造一个空的树映射,该映射使用其关键字的自然顺序来排序。
(2)TreeMap(Comparator comp) :构造一个空的基于树的映射,该映射通过使用Comparator comp来排序。
(3)TreeMap(Map m) :用从m的输入初始化树映射,该映射使用关键字的自然顺序来排序。
(4)TreeMap(SortedMap sm) :用从sm的输入来初始化一个树映射,该映射将按与sm相同的顺序来排序。

TreeMap实现SortedMap并且扩展AbstractMap,而它本身并没有另外定义其他的方法。

package com.xy.map;

import java.util.Collection;
import java.util.Iterator;
import java.util.TreeMap;

public class TreeMapDemo1 {
	public static void main(String[] args) {
		// 创建TreeMap对象
		TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
		// 加入元素到TreeMap中
		tm.put(10000-2000, "小红");
		tm.put(10000-1500, "小四");
		tm.put(10000-2500, "小明");
		tm.put(10000-5000, "小光");
		Collection<String> col = tm.values();
		Iterator<String> itr = col.iterator();
		System.out.println("工资由低到高:");
		while(itr.hasNext()) {
			System.out.println(itr.next());
		}
	}
}

【结果】
在这里插入图片描述

3、比较方法

TreeSet和TreeMap都按排序顺序存储元素。然而,更为“个性化”的排序顺序则需使用特定的比较方法。

通常在默认的情况下,这些类通过使用被Java称之为“自然顺序”的顺序存储它们的元素,而这种顺序通常也是你所需要的(A在B的前面,1在2的前面,等等)。如果需要用不同的方法对元素进行排序,可以在构造集合或映射时,指定一个Comparator对象(详细请参见第七部分比较器)。这样做为开发者提供了一种精确控制如何将元素储存到排序类集和映射中的能力。

下面是一个说明定制的比较方法能力的例子。该例子实现compare( )方法以便它按照正常顺序的逆向进行操作。因此,它使得一个树集合按逆向的顺序进行存储。

package com.xy.compare;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

class MyComp implements Comparator<Object> {
	public int compare(Object obj1, Object obj2) {
		String aStr, bStr;
		aStr = (String)obj1;
		bStr = (String)obj2;
		return bStr.compareTo(aStr);	// 注意是bStr调用的,不是aStr
	}
	
}
public class ComparatorDemo2 {
	public static void main(String[] args) {
		// 创建一个TreeSet对象
		TreeSet<String> ts = new TreeSet<String>(new MyComp());
		// 向TreeSet对象中加入内容
		ts.add("C");
		ts.add("A");
		ts.add("B");
		ts.add("E");
		ts.add("F");
		ts.add("D");
		// 得到Iterator的实例化对象
		Iterator<String> itr = ts.iterator();
		// 显示全部内容
		while(itr.hasNext()) {
			Object element = itr.next();
			System.out.print(element + " ");
		}
	}
}

【结果】
在这里插入图片描述
仔细观察实现Comparator并覆写compare()方法的MyComp类(正如前面所解释的那样,覆写equals( )方法既不是必需的,也不是常用的)。
在compare( )方法内部,String方法compareTo( )比较两个字符串。然而由bStr而不是aStr调用compareTo( )方法,会导致比较的结果被逆向。

对应一个更实际的例子:下面是用TreeMap程序实现存储账目资产平衡表例子的程序。下面的程序按姓对账目进行排序。为了实现这种功能,程序使用了比较方法来比较每一个账目下姓的先后顺序,得到的映射是按姓进行排序的。

package com.xy.compare;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

class Employee implements Comparator<Object> {
	public int compare(Object obj1, Object obj2) {
		int k;
		String aStr, bStr;
		aStr = (String)obj1;
		bStr = (String)obj2;
		k = aStr.compareTo(bStr);
		if(k == 0) {	// 相等
			return aStr.compareTo(bStr);
		}
		else
			return k;
	}
	
}
public class ComparatorDemo3 {
	public static void main(String[] args) {
		// 创建TreeMap对象
		TreeMap<String, Double> tm = new TreeMap<String, Double>(new Employee());
		// 加入元素到TreeMap中
		tm.put("John Doe", new Double(3434.34));
		tm.put("Tom Smith", new Double(123.22));
		tm.put("Jane Baker", new Double(1378.00));
		tm.put("Todd Hall", new Double(99.22));
		tm.put("Ralph Smith", new Double(-19.08));
		Set<Entry<String, Double>> set = tm.entrySet();
		Iterator<Entry<String, Double>> itr = set.iterator();
		while(itr.hasNext()) {
			Map.Entry<String, Double> me = (Map.Entry<String, Double>)itr.next();
			System.out.println(me.getKey() + " : " + me.getValue());
		}
		System.out.println();
		// 让John Doe中的值增加1000
		double balance = (Double)tm.get("John Doe").doubleValue();
		// 用新值替换掉旧值
		tm.put("John Doe", new Double(balance + 1000));
		System.out.println("John Doe现在的资金: " + tm.get("John Doe"));
	}
}

【结果】
在这里插入图片描述

4、Map集合的输出

Iterator接口中,我们强调过,若想输出集合的元素,可直接使用Iterator,那么在之前所有的集合都是Collection接口的子类,并且在Collection接口之中也定义了iterator()方法。但可是Map接口中却没有定义iterator()方法,所以现在如果要使用Iterator接口进行Map接口输出的话,就必须首先清楚Collection和Map接口保存对象的形式上的区别。

(1)Collection中的每一个元素都是一个独立的对象;
(2)Map中的每一个元素都是Key和Value“结伴而行”的组合对象——也就是所谓的“偶对象”。

下面可通过保存图观察形式上的区别:
在这里插入图片描述

Map.Entry是Map中定义的一个内部接口,而且这个接口是一个使用了static定义的外部接口,在这个接口之中定义了两个非常重要的方法。
(1)取得对应的Key的方法。public K getKey();
(2)取得对应的Value的方法。public V getValue();

那么清楚了Map.Entry的作用之后,下面就可以采用如下的步骤进行Map的Iterator输出了:
(1)通过Map接口之中entrySet()方法将Map集合变为Set集合,Set之中的泛型类型为Map. Entry;
(2)利用Set接口之中的iterator()方法取得Iterator接口对象,此时的泛型类型依然为Map.Entry;
(3)利用Iterator迭代出每一个Map.Entry对象,再使用getKey()和getValue()方法取出内容。

package com.xy.map;

import java.util.Map;
import java.util.Set;
import java.util.HashMap;
import java.util.Iterator;

public class IteratorMapDemo1 {
	public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		map.put(1, "小三");
		map.put(2, "小四");
		map.put(3, "小五");
		Set<Map.Entry<Integer, String>> set = map.entrySet();
		Iterator<Map.Entry<Integer, String>> itr = set.iterator();
		while(itr.hasNext()) {
			Map.Entry<Integer, String> me = itr.next();
			System.out.println(me.getKey() + " : " + me.getValue());
		}
		
	}
}

【结果】
在这里插入图片描述

内容总结:本文通过阅读CSDN中各位大佬的博客,做笔记加复制粘贴介绍了安卓中的Bitmap和Canvas还有java中的映射相关的一部分知识,,后续内容可以继续追踪博主的后续文章,或许会介绍相关的内容,如果没介绍,请用力踢一脚,好让摸鱼的博主积极主动的去认识错误并及时改正,在发光发热的道路上越走越远……如果有好看的运营小姐姐,也不要吝啬把微信推给我,万一您推荐了那个真命女子,博主后大半辈子感谢你大半辈子。

表情网站:🎁 Emoji cheat sheet for GitHub, Basecamp, Slack & more (webfx.com)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NoSuchManException

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值