Android自定义视图中图片的处理

作者:撩得Android一次心动 时间:2023-06-29 12:07:27 

所谓游戏,本质就是提供更逼真的、能模拟某种环境的用户界面,并根据某种规则来响应用户操作。为了提供更逼真的用户界面,需要借助于图形、图像处理。

从广义的角度来看,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 例子

Android自定义视图中图片的处理

下面开发一个查看/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.Android9新增的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;
       });
   });

来源:https://blog.csdn.net/indeedes/article/details/125196956

标签:Android,图片,自定义视图
0
投稿

猜你喜欢

  • Java实现Andriod带看括弧的计算器代码

    2023-04-06 09:36:00
  • C#如何调用MFC 窗口 DLL

    2022-04-14 09:57:51
  • Android采用双缓冲技术实现画板

    2022-05-28 15:55:58
  • Unity使用摄像机实现望远镜效果

    2021-06-07 23:30:26
  • 你知道jdk竟有4个random吗

    2022-06-14 23:37:08
  • Android实现闪屏页效果

    2022-01-17 01:21:47
  • Android实现基本功能的新闻应用

    2022-01-07 18:30:06
  • Android studio报: java.lang.ExceptionInInitializerError 错误

    2022-08-14 14:21:30
  • idea打包java可执行jar包的实现步骤

    2022-07-30 02:57:48
  • WPF快速入门教程之绑定Binding

    2021-10-10 15:32:00
  • android中webview控件和javascript交互实例

    2023-09-06 14:09:28
  • Maven发布封装到中央仓库时候报错:no default secret key

    2022-09-18 17:48:43
  • 解决Jackson解析嵌套类问题(MismatchedInputException)

    2023-07-26 03:09:31
  • C#调用webservice接口的最新方法教程

    2022-12-22 05:07:27
  • Android开发使用HttpURLConnection进行网络编程详解【附源码下载】

    2022-01-11 23:27:37
  • Spring中注解方式的异步请求

    2023-11-30 18:53:54
  • Spring工作原理简单探索

    2023-04-26 10:30:56
  • c# split分隔字符串使用方法

    2023-04-12 18:00:54
  • java实现文件上传下载

    2023-11-23 09:41:18
  • mybatis原理概述入门教程

    2023-10-08 13:10:57
  • asp之家 软件编程 m.aspxhome.com