編輯:關於Android編程
Android的原生控件並不支持播放GIF格式的圖片。我們都知道,在Android中如果想要顯示一張圖片,可以借助ImageView來完成,但是如果將一張GIF圖片設置到ImageView裡,它只會顯示這張圖片的第一幀,不會產生任何的動畫效果。今天我們來編寫一個自定義的增強型ImageView(繼承ImageView),可以播放GIF格式的圖片,暫且叫做GifImageView吧。
1.自定義屬性
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="GifImageView"> <attr name="auto_play" format="boolean"></attr> </declare-styleable> </resources>
2.自定義View中獲取屬性值
private Movie mMovie;//播放動畫需要用到的,系統類 private int mImageWidth;//動畫的imageview的寬度 private int mImageHeight;//動畫imageview的高度 private long mMovieStart = 0;// 播放開始 private boolean isAutoPlay;//是否自動播放 private Bitmap mStartPlay;//開始按鈕 private boolean isPlaying=false;//記錄是否正在播放 private float mScale;//圖片的縮放比 private int mMeasuredGifWidth;//縮放後圖片寬 private int mMeasuredGifHeight;//縮放後圖片高 ... private void init(Context context, AttributeSet attrs) { TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.GifImageView); // 通過反射拿布局中src的資源id,所以gif文件需要放在布局的src中 int resourceId = getResourceId(attributes, context, attrs); if (resourceId != 0) { // 說明是gif動畫 // 1.將resourcesId變成流 // 2.用Move來decode解析流 // 3.獲得bitmap的長寬 InputStream is = getResources().openRawResource(resourceId); mMovie = Movie.decodeStream(is); if (mMovie != null) { Bitmap bitmap = BitmapFactory.decodeStream(is); mImageWidth = bitmap.getWidth(); mImageHeight = bitmap.getHeight(); // 用完釋放 bitmap.recycle(); // 獲得是否允許自動播放,如果不允許自動播放,則初始化播放按鈕 isAutoPlay = attributes.getBoolean(R.styleable.GifImageView_auto_play, false); if (!isAutoPlay) { mStartPlay = BitmapFactory.decodeResource(getResources(),R.drawable.start_play); setOnClickListener(this); } } } //回收資源 attributes.recycle(); } /** * 通過反射拿布局中src的資源id * * @param attrs * @param context * @param attributes */ private int getResourceId(TypedArray attributes, Context context, AttributeSet attrs) { try { Field filed = TypedArray.class.getDeclaredField("mValue"); filed.setAccessible(true); TypedValue typeValue = (TypedValue) filed.get(attributes); return typeValue.resourceId; } catch (Exception e) { e.printStackTrace(); } } return 0; }
3.重寫onMesure()
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mMovie != null) { /* * Calculate horizontal scaling */ float scaleW = 1f; int measureModeWidth = MeasureSpec.getMode(widthMeasureSpec); if (measureModeWidth != MeasureSpec.UNSPECIFIED) { int maximumWidth = MeasureSpec.getSize(widthMeasureSpec); scaleW = (float) mImageWidth / (float) maximumWidth; } /* * calculate vertical scaling */ float scaleH = 1f; int measureModeHeight = MeasureSpec.getMode(heightMeasureSpec); if (measureModeHeight != MeasureSpec.UNSPECIFIED) { int maximumHeight = MeasureSpec.getSize(heightMeasureSpec); scaleH = (float) mImageHeight / (float) maximumHeight; } /* * calculate overall scale */ mScale = 1f / Math.max(scaleH, scaleW); mMeasuredGifWidth = (int) (mImageWidth * mScale); mMeasuredGifHeight = (int) (mImageHeight * mScale); setMeasuredDimension(mMeasuredGifWidth, mMeasuredGifHeight); } }
4.重寫onDraw()
@Override protected void onDraw(Canvas canvas) { if (mMovie == null) { // mMovie等於null,說明是張普通的圖片,則直接調用父類的onDraw()方法 super.onDraw(canvas); } else { // mMovie不等於null,說明是張GIF圖片 if (isAutoPlay) { // 如果允許自動播放,就播放 playMovie(canvas); invalidate(); } else { // 不允許自動播放的話 // 1.判斷是否正在播放 // 2.獲得第一幀的圖像 // 3.然後添加播放按鈕 if (isPlaying) { // 如果正在播放就playmoive繼續播放 if (playMovie(canvas)) { isPlaying = false; } invalidate(); } else { // 第一幀 mMovie.setTime(0); canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.scale(mScale, mScale); mMovie.draw(canvas, 0, 0);// 畫 canvas.restore(); // 繪制開始按鈕 int offsetW = (mMeasuredGifWidth - mStartPlay.getWidth()) / 2; int offsetH = (mMeasuredGifHeight - mStartPlay.getHeight()) / 2; canvas.drawBitmap(mStartPlay, offsetW, offsetH, null); } } } } /** * 播放gif動畫 * * @param canvas */ private boolean playMovie(Canvas canvas) { // 1.獲取播放的時間 // 2.如果開始start=0,則認為是開始 // 3.記錄播放的時間 // 4.設置進度 // 5.畫動畫 // 6.如果時間大於了播放的時間,則證明結束 long now = SystemClock.uptimeMillis(); if (mMovieStart == 0) { mMovieStart = now; } int duration = mMovie.duration(); if (duration == 0) { duration = 1000; } //記錄gif播放了多少時間 int relTime = (int) ((now - mMovieStart) % duration); mMovie.setTime(relTime);// 設置時間 canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.scale(mScale, mScale); mMovie.draw(canvas, 0, 0);// 畫 canvas.restore(); if ((now - mMovieStart) >= duration) { // 結束 mMovieStart = 0; return true; } return false; }
5.添加點擊事件
@Override public void onClick(View v) { if(v.getId()==getId()){ isPlaying=true; invalidate(); } }
還有一點需要注意,有些4.0以上系統的手機啟動了硬件加速功能之後會導致GIF動畫播放不出來,因此我們需要在AndroidManifest.xml中去禁用硬件加速功能,可以通過指定android:hardwareAccelerated=false來完成。
--------------------------------------------------------------------------------
現在我們來看看運行後效果如何吧,
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:attr="http://schemas.android.com/apk/res/com.hx.gifimageview" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.hx.gifimageview.GifImageView android:layout_width="150dip" android:layout_height="150dip" android:layout_margin="10dp" android:src="@drawable/shulan" attr:auto_play="false" /> <com.hx.gifimageview.GifImageView android:layout_width="150dip" android:layout_height="150dip" android:layout_margin="10dp" android:src="@drawable/shulan" attr:auto_play="true" /> <com.hx.gifimageview.GifImageView android:layout_width="150dip" android:layout_height="150dip" android:layout_margin="10dp" android:src="@drawable/jingtai" attr:auto_play="true" /> </LinearLayout>
圖一的auto_play屬性為false,會顯示第一幀和一個播放按鈕,點擊後Gif圖片會自動運行。
圖二的auto_play屬性為true,會自動循環播放Gif。
圖三我們給的資源是靜態圖片,因為自定義View繼承ImageView,所以具備ImageView所有特性,因此也能顯示靜態圖片。
源碼下載:http://xiazai.jb51.net/201609/yuanma/GifImageView(jb51.net).rar
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
一、看效果二、添加compile 'com.orhanobut:logger:1.8'三、使用方法在自定義Application的onCreate方法中L
根據人眼視覺殘留現象,連續播放一些列的圖像,形成動畫效果。Android中的動畫:游戲:利用自定義View的繪制方法,開啟線程頻繁的刷新界面,形成動畫; Android
Android程序是怎麼從源碼變成可以安裝使用的apk的流程官方版詳細版上面就是一個關於構建過程的一個典型的流程圖。輸出生成的apk在app/build/outputs/
MainActivity如下:package cc.textview5; import android.os.Bundle; import android.text.Te