当前位置:网站首页>自定义视图:图形与图像的处理(一):使用简单图片
自定义视图:图形与图像的处理(一):使用简单图片
2022-06-10 16:22:00 【撩得Android一次心动】
Android系统提供了ImageView显示普通的静态图片,也提供了AnimationDrawable来开发逐帧动画,还可通过Animation对普通图片使用补间动画。图形、图像处理不仅对Android系统的应用界面非常重要,而且Android系统上的益智类游戏、2D游戏都需要大量的图形、图像处理。
所谓游戏,本质就是提供更逼真的、能模拟某种环境的用户界面,并根据某种规则来响应用户操作。为了提供更逼真的用户界面,需要借助于图形、图像处理。
从广义的角度来看,Android应用中的图片不仅包括*.png、*.jpg、 *.gif等各种格式的位图,也包括使用XML资源文件定义的各种Drawable对象。
1.使用Drawable对象
为Android应用增加了Drawable资源之后,Android SDK会为这份资源在R清单文件中创建一个索引项:R.drawable.file_name。
获取方式:
- 在XML资源文件中通过@drawablelfile_name访问该Drawable对象,
- 在Java代码中通过R.drawable.file_name访问该Drawable对象。
需要指出的是,R.drawable.file_name是一个int类型的常量,它只代表Drawable对象的ID,如果Java程序中需要获取实际的Drawable对象,则可调用Resources的getDrawable (int id)方法来实现。
2.Bitmap和BitmapFactory
Bitmap代表一个位图,BitmapDrawable里封装的图片就是一个Bitmap对象。
两者之间的转换:
//把一个Bitmap对象包装成BitmapDrawable对象 BitmapDrawable drawable = new BitmapDrawable (bitmap) ;如果需要获取BitmapDrawable所包装的Bitmap对象,则可调用BitmapDrawable的getBitmap ()方法,如下面的代码所示:
//获取BitmapDrawable所包装的Bitmap 对象 Bitmap bitmap = drawable.getBitmap();
新建Bitmap对象的一些方法:
- createBitmap (Bitmap source,int x, int y,int width,int height):从源位图source的指定坐标点(给定x、y)开始,从中“挖取"宽width、高height的一块出来,创建新的Bitmap对象。
- createScaledBitmap (Bitmap src, int dstWidth,int dstHeight,boolean filter) :对源位图src进行缩放,缩放成宽dstWidth、高dstHeight的新位图。 filter是过滤器。
- createBitmap (int width,int height,Bitmap.Config config):创建一个宽width、高height的新位图。
- createBitmap (Bitmap source,int x, int y, int width,int height,Matrixm, boolean filter):从源位图source 的指定坐标点(给定x、y)开始,从中“挖取"宽 width、高height的一块出来,创建新的Bitmap对象,并按Matrix指定的规则进行变换。
Bitmap.Config类,在Bitmap类里createBitmap(int width, int height, Bitmap.Config config)方法里会用到,打开个这个类一看 :枚举变量
public static final Bitmap.Config ALPHA_8
public static final Bitmap.Config ARGB_4444
public static final Bitmap.Config ARGB_8888
public static final Bitmap.Config RGB_565
BitmapFactory是一个工具类,它提供了大量的方法,这些方法可用于从不同的数据源来解析、创建Bitmap对象。BitmapFactory包含了如下方法。
- decodeByteArray (byte[]data,int offset,int length)︰从指定字节数组的offset位置开始,将长度为length的字节数据解析成Bitmap对象。
- decodeFile (String pathName) :从pathName指定的文件中解析、创建Bitmap对象。
- decodeFileDescriptor (FileDescriptor fd):用于从FileDescriptor对应的文件中解析、创建Bitmap对象。
- decodeResource (Resources res,int id) :用于根据给定的资源ID从指定资源中解析、创建Bitmap对象。
- decodeStream (InputStream is):用于从指定输入流中解析、创建Bitmap对象。
对于创建而言,对应的就是回收了。如果系统不停的去解析、创建Bitmap对象,可能由于创建的Bitmap所占用的内存还没回收,而导致OOM。
- boolean isRecycled ():返回该Bitmap对象是否已被回收。
- void recycle () :强制一个Bitmap对象立即回收自己。
如果Android应用需要访问其他存储路径(比如SD卡)里的图片,那么都需要借助于BitmapFactory来解析、创建Bitmap对象。
2.1 例子

下面开发一个查看/assets/目录下图片的图片查看器,当用户单击该按钮时程序会自动去搜寻/assets/目录下的下—张图片。此处不再给出界面布局代码,该程序的代码如下。
public class Test4Activity extends Activity {
String[] images = null;
AssetManager assets = null;
int currentImg = 0;
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test4_acitvity);
image = findViewById(R.id.test4_iv);
Button next = findViewById(R.id.test4_bt_next);
try {
assets = getAssets();
//获取assets目录目录下的所有文件
images =assets.list("");
} catch (IOException e) {
e.printStackTrace();
}
//按钮事件
next.setOnClickListener(view -> {
//如果发生数组越界
if(currentImg >= images.length){
currentImg = 0;
}
//找到下一个图片文件
while (!images[currentImg].endsWith(".png")&&!images[currentImg].endsWith(".jpg")
&&!images[currentImg].endsWith(".gif")){
currentImg++;
//如果已经发生了数组越界
if(currentImg >= images.length){
currentImg = 0;
}
}
InputStream assetFile = null;
try {
//打开指定资源对应的输入流
assetFile = assets.open(images[currentImg++]);
} catch (IOException e) {
e.printStackTrace();
}
BitmapDrawable bitmapDrawable = (BitmapDrawable) image.getDrawable();
//如果图片还未回收,先强制回收该图片
if(bitmapDrawable != null&&!bitmapDrawable.getBitmap().isRecycled()){
bitmapDrawable.getBitmap().recycle();
}
//改变ImageView显示图片
//调用了BitmapFactory从指定输入流解析并创建Bitmap
image.setImageBitmap(BitmapFactory.decodeStream(assetFile));
});
}
}2.2 额外知识点(assets)
系统为每一个新设计的程序提供了/assets文件夹,这个文件夹保存的文件能够打包在程序里。
/res和/assets的不同点是,android不为/assets下的文件生成ID。假设使用/assets下的文件,须要指定文件的路径和文件名称。怎样访问/assets下的内容?
例如,假设在assets目录下有一个名称为filename的文件,那么就可以使用以下代码来访问它:
AssetManager assset= getAssets();
InputStream is = assset.open("filename");2.3 优秀思想学习,让代码更严谨
1.发现这代码一点黄色都没有,证明很严谨。
注意为什么button放在了里面,而imageView放在了外面。
将button放在外面会有Field can be converted to a local variable的警告,意思是检测到这个变量可以使用局部变量替换,建议删除并写成局部变量。就是其他地方也没有使用到它,没有必要声明成成员变量。
2.设计到数组访问,一定要防止其数组越界。上面还搞了两个。
assetFile = assets.open(images[currentImg++]);此时进入到open的必定是图片资源的name,用了之后currentImg自加,探索下一个图片。第一个防止其数组越界的判断就是防这里的;第二是对应着判断不是图片资源的++。但是这个代码还有问题:假如里面有资源,但是都不是图片资源。那就会进入死循环
3.在显示图片之前,一定要释放之前的Bitmap,以免OOM
释放的判断的条件是使用Bitmap的封装类。
3.Android 9 新增的 ImageDecoder
Android 9 引入了ImageDecoder、OnHanderDecodedListener等API,提供了更强大的图片解码支持,可以解码png、jpeg等静态图片和gif、webp等动画图片。另外。还新增了支持HEIF格式:
HEIF格式:这种压缩格式据有超高的压缩比例,相比JPEG,可以压缩到其一半大小,而且可以保证其近似的图片质量。
当使用 ImageDecoder 解码gif、webp等动画图片时,会返回一个AnimatedImageDrawable对象,调用AnimatedImageDrawable对象的start()方法即可开始执行动画。
ImageDecoder 解码图片的方式:
- 调用 ImageDecoder 的重载的 createSource 方法来创建 Source 对象。根据不同的图片来源, createSource 方法有不同的重载模式。
- 调用ImageDecoder 的 decodeDrawabIe(Source) or decodeBitmap(Source)方法来读取代表图片的 Drawable或 Bitmap对象。
在第二步时,可以额外传入一个 OnHanderDecodedListener 参数,该参数代表了监听器,该监听器要实现一个 onHanderDecoded(ImageDecoder,ImageInfo,Source)方法,可以对ImageDecoder进行额外的设置,也可以通过 ImageInfo 获取被解码图片的信息。
3.1 例子
public class Test5Activity extends AppCompatActivity {
//说白了只有api 28 之后的才进的来
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test5);
//获取对象
TextView textView = findViewById(R.id.test5_tv);
ImageView imageView = findViewById(R.id.test5_iv);
//创建 imageDecoder.Source对象
//第一步:
ImageDecoder.Source source = ImageDecoder.createSource(getResources(),R.drawable.viewgif);
try {
//第二步:执行decodeDrawable()方法获取Drawable对象
@SuppressLint({"WrongThread", "SetTextI18n"})
Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{
//通过 info 参数获取被解码图片的信息
textView.setText("图片的原始宽度:"+info.getSize().getWidth()+
"\n"+"图片原始宽高"+info.getSize().getHeight());
//设置图片解码之后的缩放大小
decoder.setTargetSize(600,580);
});
imageView.setImageDrawable(drawable);
//如果drawable 是AnimatedImageDrawable的实例,则执行动画
if(drawable instanceof AnimatedImageDrawable){
((AnimatedImageDrawable) drawable).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}与传统的BitmapFactory相比,ImageDecoder 甚至可以解码包含不完整或错误的图片,如果希望显示ImageDecoder解码出错之前的部分图片,则可通过为 ImageDecoder没置OnPartialImageListener监听器来实现。例如如下代码片段:
//先用Lambda 表达式作为OnHeaderDecodeListener监听器
Drawable drawable = ImageDecoder.decodeDrawable(source,(decoder, info, s) ->{
//为ImageDecoder 设置 OnPartialImageListener 监听器(Lambda 表达式)
decoder.setOnPartialImageListener(e->{
....
//return true 表明即使不能完整地解码全部图片也返回Drawable或Bitmap
return true;
});
});边栏推荐
- [BSP video tutorial] BSP video tutorial issue 17: single chip microcomputer bootloader topic, startup, jump configuration and various usage of debugging and downloading (2022-06-10)
- Station B doesn't want to be a "conscience aiyouteng"
- Fabric.js 精简输出的JSON
- 几个对程序员的误解,害人不浅!
- 新思科技在《 2022 年 Gartner 应用安全测试关键能力报告》中表现优异 在五个常见用例中荣获最高分
- Overseas data centers need to be prepared for unpredictable disasters
- 复利最高的保险产品是什么?一年要交多少钱?
- Knowledge based bert: a method to extract molecular features like a computational chemist
- Fabric.js 元素被选中时保持原有层级
- 提升园区服务水平,优化营商环境该从哪些方面入手
猜你喜欢

大山深处的孩子,正在看见更远的星空

Intelligent scenic spot video monitoring 5g intelligent light pole gateway networking integrated pole

新思科技在《 2022 年 Gartner 应用安全测试关键能力报告》中表现优异 在五个常见用例中荣获最高分

ADB is not an internal or external command, nor is it a runnable program or batch file

【报表工具的第二次革命】基于SPL语言优化报表结构、提升报表运算性能

“禁塑令”下,中宝新材深挖可降解塑料,港交所买单吗?

Docker安装Redis镜像详细步骤(简单易懂,适合新手快速上手)

A few misunderstandings about programmers are very harmful!

For more than 20 years, there are only Durex, Okamoto and jasbon in the condom market

Institute of automation, Chinese Academy of Sciences: a review of the latest visual language pre training
随机推荐
Fabric. JS zoom canvas
MFC basic knowledge and course design ideas
A few misunderstandings about programmers are very harmful!
Smart Scenic Spot Video Monitoring 5G Smart lamp Gateway Network Integrated pole
每日一题-1287. 有序数组中出现次数超过25%的元素
2022年茶艺师(中级)操作证考试题库及模拟考试
[proteus simulation] ds18b20+ alarm temperature adjustable +lm016 display
Postman common assertions
Knowledge based bert: a method to extract molecular features like a computational chemist
VBA divides strings, stores them in an array, writes them to a file, and saves them
Carry forward the past and forge ahead into the future, multiple residuals | densenet (I)
Xinsi technology performed well in the Gartner application security test key capability report 2022 and won the highest score among the five common use cases
MySQL如何修改字段类型和字段长度
运筹说 第64期丨动态规划奠基人——理查德·贝尔曼
直播预告 | 社交新纪元,共探元宇宙社交新体验
Basic use of pycharm
接口测试学习笔记
mysql数据库实现设置字段长度
谁在使用我的服务器?在干什么?什么时候?
Fiddler set breakpoint