范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Android开发之ImageView播放GIF动画实例

  Android开发之ImageView播放GIF动画实例
  Android的原生控件并不支持播放GIF格式的图片,如果想在Android中显示一张GIF动态图片,可以利用 ImageView控件来完成,但是放进去之后,你会发现,ImageView它只会显示这张图片的第一帧,不会产生任何的动画效果。我们必须通过自定义控件的方式来实现ImageView播放GIF 图片的功能。
  首先我们来编写一个PowerImageView控件,让它既能支持ImageView控件原生的所有功能,同时还可以播放GIF动态图片。
  先新建一个项目PowerImageViewTest,这里使用Android 4.0+Eclipse。
  由于是要自定义控件,会需要一些自定义的控件属性,因此我们需要在values目录下新建一个attrs.xml的文件,在这个文件中添加项目需要的自定义属性。
  这里我们目前暂时只需要一个自动播放auto_play属性,XML文件代码如下:
  <?xml version="1.0" encoding="utf-8"?>
  
  
  
  这个文件完成之后,下面我们来开始编写主类PowerImageView类,由于PowerImageView类需要支持ImageView的所有功能,我们必须要让PowerImageView继承自ImageView,代码如下:
  public class PowerImageView extends ImageView implements OnClickListener {
  /**
  * 播放GIF动画的关键类
  */
  private Movie mMovie;
  /**
  * 开始播放按钮图片
  */
  private Bitmap mStartButton;
  /**
  * 记录动画开始的时间
  */
  private long mMovieStart;
  /**
  * GIF图片的宽度
  */
  private int mImageWidth;
  /**
  * GIF图片的高度
  */
  private int mImageHeight;
  /**
  * 图片是否正在播放
  */
  private boolean isPlaying;
  /**
  * 是否允许自动播放
  */
  private boolean isAutoPlay;
  /**
  * PowerImageView构造函数。
  *
  * @param context
  */
  public PowerImageView(Context context) {
  super(context);
  }
  /**
  * PowerImageView构造函数。
  *
  * @param context
  */
  public PowerImageView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
  }
  /**
  * PowerImageView构造函数,在这里完成所有必要的初始化操作。
  *
  * @param context
  */
  public PowerImageView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PowerImageView);
  int resourceId = getResourceId(a, context, attrs);
  if (resourceId != 0) {
  // 当资源id不等于0时,就去获取该资源的流
  InputStream is = getResources().openRawResource(resourceId);
  // 使用Movie类对流进行解码
  mMovie = Movie.decodeStream(is);
  if (mMovie != null) {
  // 如果返回值不等于null,就说明这是一个GIF图片,下面获取是否自动播放的属性
  isAutoPlay = a.getBoolean(R.styleable.PowerImageView_auto_play, false);
  Bitmap bitmap = BitmapFactory.decodeStream(is);
  mImageWidth = bitmap.getWidth();
  mImageHeight = bitmap.getHeight();
  bitmap.recycle();
  if (!isAutoPlay) {
  // 当不允许自动播放的时候,得到开始播放按钮的图片,并注册点击事件
  mStartButton = BitmapFactory.decodeResource(getResources(),R.drawable.start_play);
  setOnClickListener(this);
  }
  }
  }
  }
  @Override
  public void onClick(View v) {
  if (v.getId() == getId()) {
  // 当用户点击图片时,开始播放GIF动画
  isPlaying = true;
  invalidate();
  }
  }
  @Override
  protected void onDraw(Canvas canvas) {
  if (mMovie == null) {
  // mMovie等于null,说明是张普通的图片,则直接调用父类的onDraw()方法
  super.onDraw(canvas);
  } else {
  // mMovie不等于null,说明是张GIF图片
  if (isAutoPlay) {
  // 如果允许自动播放,就调用playMovie()方法播放GIF动画
  playMovie(canvas);
  invalidate();
  } else {
  // 不允许自动播放时,判断当前图片是否正在播放
  if (isPlaying) {
  // 正在播放就继续调用playMovie()方法,一直到动画播放结束为止
  if (playMovie(canvas)) {
  isPlaying = false;
  }
  invalidate();
  } else {
  // 还没开始播放就只绘制GIF图片的第一帧,并绘制一个开始按钮
  mMovie.setTime(0);
  mMovie.draw(canvas, 0, 0);
  int offsetW = (mImageWidth - mStartButton.getWidth()) / 2;
  int offsetH = (mImageHeight - mStartButton.getHeight()) / 2;
  canvas.drawBitmap(mStartButton, offsetW, offsetH, null);
  }
  }
  }
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  if (mMovie != null) {
  // 如果是GIF图片则重写设定PowerImageView的大小
  setMeasuredDimension(mImageWidth, mImageHeight);
  }
  }
  /**
  * 开始播放GIF动画,播放完成返回true,未完成返回false。
  *
  * @param canvas
  * @return 播放完成返回true,未完成返回false。
  */
  private boolean playMovie(Canvas canvas) {
  long now = SystemClock.uptimeMillis();
  if (mMovieStart == 0) {
  mMovieStart = now;
  }
  int duration = mMovie.duration();
  if (duration == 0) {
  duration = 1000;
  }
  int relTime = (int) ((now - mMovieStart) % duration);
  mMovie.setTime(relTime);
  mMovie.draw(canvas, 0, 0);
  if ((now - mMovieStart) >= duration) {
  mMovieStart = 0;
  return true;
  }
  return false;
  }
  /**
  * 通过Java反射,获取到src指定图片资源所对应的id。
  *
  * @param a
  * @param context
  * @param attrs
  * @return 返回布局文件中指定图片资源所对应的id,没有指定任何图片资源就返回0。
  */
  private int getResourceId(TypedArray a, Context context, AttributeSet attrs) {
  try {
  Field field = TypedArray.class.getDeclaredField("mValue");
  field.setAccessible(true);
  TypedValue typedValueObject = (TypedValue) field.get(a);
  return typedValueObject.resourceId;
  } catch (Exception e) {
  e.printStackTrace();
  } finally {
  if (a != null) {
  a.recycle();
  }
  }
  return 0;
  }
  }
  这个类的代码注释已经非常详细了,我再来简单地解释一下。可以看到,我们重写了ImageView中所有的构建函数,使得 PowerImageView的用法可以和ImageView完全相同。在构造函数中,则是对所有必要的数据进行了初始化操作。首先,我们调用了 getResourceId()方法去获取图片资源对应的id值,在getResourceId()方法内部是通过Java的反射机制来进行获取的。得到了图片资源的id后,我们将它转换成InputStream,然后传入到Movie.decodeStream()方法中以解码出Movie对象。如果得到的Movie对象等于null,说明这是一张普通的图片资源,就不再进行任何特殊处理,因为父类ImageView都帮我们处理好了。如果得到的 Movie对象不等于null,则说明这是一张GIF图片,接着就要去获取是否允许自动播放、图片的宽高等属性的值。如果不允许自动播放,还要给播放按钮 注册点击事件,默认是不允许自动播放的。
  接下来会进入到onMeasure()方法中。在这个方法中我们进行判断,如果这是一张GIF图片,则需要将PowerImageView的宽高重定义,使得控件的大小刚好可以放得下这张GIF图片。
  再往后就会进入到onDraw()方法中。在这个方法里同样先判断当前是一张普通的图片还是GIF图片,如果是普通的图片就直接调用 super.onDraw()方法交给ImageView去处理就好了。如果是GIF图片,则先判断该图是否允许自动播放,允许的话就调用 playMovie()方法去播放GIF图片就好,不允许的话则会先在PowerImageView中绘制该GIF图片的第一帧,并在图片上绘制一个播放 按钮,当用户点击了播放按钮时,再去调用playMovie()方法去播放GIF图片。
  下面我们来看看playMovie()方法中是怎样播放GIF图片的吧。可以看到,首先会对动画开始的时间做下记录,然后对动画持续的时间做下记 录,接着使用当前的时间减去动画开始的时间,得到的时间就是此时PowerImageView应该显示的那一帧,然后借助Movie对象将这一帧绘制到屏 幕上即可。之后每次调用playMovie()方法都会绘制一帧图片,连贯起来也就形成了GIF动画。注意,这个方法是有返回值的,如果当前时间减去动画 开始时间大于了动画持续时间,那就说明动画播放完成了,返回true,否则返回false。
  完成了PowerImageView的编写,下面我们就来看一看如何使用它吧,其实非常简单,打开或新建activity_main.xml,代码如下所示:
  
  
  
  可以看到,PowerImageView的用法和ImageView几乎完全一样,使用android:src属性来指定一张图片即可,这里指定的anim就是一张GIF图片。然后我们让PowerImageView在布局里居中显示MainActivity中的代码都是自动生成的,这里就不再贴出来了。在AndroidManifest.xml中还有一点需要注意,有些4.0 以上系统的手机启动了硬件加速功能之后会导致GIF动画播放不出来,因此我们需要在AndroidManifest.xml中去禁用硬件加速功能,可以通过指定android:hardwareAccelerated属性来完成,代码如下所示:
  <?xml version="1.0" encoding="utf-8"?>
  
  
  android:allowBackup="true"
  android:icon="@drawable/ic_launcher"
  android:label="@string/app_name"
  android:theme="@style/AppTheme"
  android:hardwareAccelerated="false"
  >
  android:name="com.example.powerimageviewtest.MainActivity"
  android:label="@string/app_name" >
  
  
  
  
  现在可以来运行一下代码了,一打开程序你就会看到GIF图片的第一帧,点击图片之后就可以播放GIF动画了。
  然后我们还可以通过修改activity_main.xml中的代码,给它加上允许自动播放的属性,代码如下所示:
  
  
  
  这里使用了刚才我们自定义的属性,通过attr:auto_play来启用和禁用自动播放功能。现在将auto_play属性指定成true后,PowerImageView上就不会再显示一个播放按钮,而是会循环地自动播放动画。不仅如此,PowerImageView还继承了ImageView原生的所有功能,只要指定的不是GIF图 片,PowerImageView表现的结果就和ImageView完全一致,现在我们来放一张普通的PNG图片,修改 activity_main.xml中的代码,如下所示:
  
  
  
  这里在src属性里面指定了一张名字为myphoto的PNG图片,图片在布局正中央显示出来了,正是普通ImageView所具备的功能。我们还可以在PowerImageView中指定android:scaleType等属性,用法和原生的ImageView完全一样。

华为P40Pro5G重新上架官方商城?售价5988元,还值得买吗?4月7日消息,华为商城重新上架了华为P40Pro8GB128GB版本,提供亮黑冰霜银零度白深海蓝晨曦金五款配色,目前官方售价5988元,与当初发布相同。目前的华为手机,能有5G功能曝旗舰功能加特小米12Ultra,小米11低价史无前例,堪称白菜机曝光配置信息基本相当齐全小米12Ultra超大杯版同样会配备LPDDR5运存和UFS3。1闪存,曝光配置信息基本相当齐全小米12Ultra超大杯版加上了最大512GB的存储,曝光配继华为之后,又一国产手机叫板苹果,结果网友的点评意外火了自从苹果手机进入中国市场,给中国的手机市场带来了不小的冲击。在北上广等一线城市,有一部苹果手机苹果电脑似乎成了标配,而在其他城市,苹果手机更成为了大家羡慕的电子产品。苹果手机在中国12512G卖7488,鸿蒙系统200倍变焦,华为P50Pro值这个价吗?现如今国内智能手机市场中,几乎所有的国产手机品牌都在进军高端手机市场,而这些机型除了硬件配置比较高以外价格方面也比较凸出。而要说价格最贵的国产手机品牌那还得是华为手机。华为因受到禁华为WatchGT3Pro曝光拥有钛合金版搭载鸿蒙系统近日消息,华为新款智能手表WatchGT3Pro的包装盒被数码博主曝光,根据包装盒来看,WatchGT3Pro整体白色的设计看上去更加干净,白色的表圈搭配金色的中框以及金色的按键看华为的强大源于毛泽东思想指导现在流行这么一句话在中国有两个公司,一个是华为,另一个就是其他。可想而知,华为在中国企业中的地位。大家都知道,华为是一个真正的高科技公司,是中国最伟大的公司之一,是一个非常有活力,vivoXNote开始预售,7英寸高端旗舰,大尺寸机型卷土重来?现在智能手机的屏幕尺寸基本都在六英寸到七英寸之间,但基本上没有达到七英寸的机型。很多手机厂商甚至都在努力把手机尺寸做得小一点,也推出了多款小屏旗舰。毕竟小屏手机更有利于单手操作,而安卓手机的福利免费使用微信双开微信已经在不知不觉影响到我们日常生活中的每一个地方,工作交流,亲情交流,朋友聚合,相信大家为了能够把工作和日常生活区分开,都注册了两个微信账号来进行区分。但是,微信又只能在一部手机苹果手机14pro系列两点值得购买距离苹果14系类还有5个多月了,很多人也是摩拳擦掌了,希望很快得到他们心心相念的14系类手机,小编今天想说的就是苹果的高端手机的系类,苹果手机14pro系列有两点值得我们购买。1。miui13稳定版第三批更新的手机出炉,2020年手机为主?miui13稳定版第三批可以更新的手机名单出炉,其实覆盖很广了?小米10青春版RedmiNote9ProRedmiNote94GRedmiK30RedmiK305GRedmiK30256GB1亿像素,从1999元降至1299元,这款落伍手机值得买随着手机市场的急剧变革,市面上的手机产品也出现了越来越多的分级,纵览整个手机市场不难发现,虽然价格高的旗舰手机拥有更好的硬件配置,但是它的销量却远远没有热门的千元机高。RedmiN
旧电脑怎么处理?在这个日新月异的时代中,现阶段电脑的更新换代的速度越来越快,而人们也极致的追求新的电脑给自己带来的享受。硬件配置电脑的外观形状变得越来约好,所以,人们就想拥有更好的电脑,而以前的老鸿蒙面世了,国人激动,友商冷淡,为什么?很简单,因为老百姓和厂商的关注点不同。鸿蒙系统的面世对华为对中国来说,是具有非凡的战略意义的,是中国科技领域迈出的具有划时代意义的一大步,普通老百姓当然非常激动。而各个厂商反应冷淡小米RedmiNote10首发RedmiK40Pro大降价,米粉如何选择?我觉得能选红米K40Pro手机的话,就不要选择红米note10系列手机,因为从定位层面一个是旗舰机,一个是千元机,当然一切都要基于预算来考虑的!在618旗舰红米K40Pro即使再降游戏本该选y7000p还是r7000p?联想拯救者笔记本里面,Y系列采用的是Intel处理器,R系列采用的是AMD处理器,而且就价格而言,Intel平台的Y系列往往会贵一些。以2021年的Y7000P和R7000P为例,家庭听音乐用什么功放好?适合你自己的就是最好的!首先你得有喜欢听什么风格的音乐?喜欢人声还是乐器,古典音乐,还是交响乐其次你的音箱的阻抗,频响范围,灵敏度等指标怎么样?最后你准备用什么设备作音源,比如说你手机存储UFS3。0和UFS3。1差多少?感谢您的阅读!UFS是什么?我觉得我们首先要搞懂这个问题。其实这个问题很好解决,它的名字叫做闪存规格。它指的是我们的手机数据读取和写入的速度。如果我们的读取和写入速度更快的话,那么为何现在币价跌了,显卡价格仍旧不能恢复正常?臭打游戏的不配拥有显卡大笑跌?跌了多少?几千的时候都有人挖,更不要说现在了而且全网算力还在涨。再加上奸商囤货。除非腰斩腰斩再腰斩!不然显卡短期内真别想降下来显卡矿机主要是挖以太坊,618购机,预算5000左右,有哪些推荐?iPhone11的信号的确是不如安卓那边,所以你如果希望信号表现好一些的话,iPhone这些机器就可以排除了,此外几款备选机器里面,Mate30系列直接排除就是了,配置落后价格还不光刻机的未来是什么?光刻机一直是被人们称作现代光学的工业之花。厂商要研发并制造出光刻机,需要投入非常高的资金资源和人力资源,这使得半导体设备行业中只有极少数的几家厂商能够制造光刻机。伴随着半导体行业的不超三千二,什么手机照相最好?看了一下题主给出的三个备选项小米10s真我GT一加8T,这几部手机都是走性价比路线,拍照都很一般呀。也就小米10s的一亿像素主摄稍微强一点,但这一亿像素的调教大家反馈都很一般,至少为什么说各国的科技需求已经开始渐渐远离美国?美国现在的种种行为,就像一个捅马蜂窝的人,美国综合实力排名暂居第一,这是无可置疑的。但它的第一又能保持多久呢?我大胆的预测一下,美国的霸权主义保持的越久越强硬,它的优势也就越快丧失