Android 顯示 Gif動態圖片的三種常用方法
阿新 • • 發佈:2019-02-15
1.首先描述下自定義控制元件的一般方法:
自定義控制元件是被創造出來,所以先要複寫它三個的構造方法,根據需求決定複寫哪個,若沒有自定義屬性,複寫只有一個引數的即可。若有自定義屬性,則可以通過obtainStyledAttributes獲得TypedArray物件,通過該物件獲得屬性並進行相應操作。然後下面的過程和畫畫差不多,我們在畫一樣東西的時候,首先要知道物品大概的樣子,也就是需要複寫onMeasure()方法,測量控制元件以及其子佈局的大小。知道物品的大概後,我們需要對其裡面的細節精雕細琢,也就是呼叫onLayout()方法,決定其子View的位置。最後就是將圖整體勾勒出來,即是呼叫onDraw()方法。這樣子控制元件大概的樣子就出來了,再根據需求增加相應藉口,回撥方法。
2.Android顯示gif的三種方式:
(1)使用Android自帶的Movie物件,將Gif當成視訊。隨著時間的變化,通過setTime方法設定需要顯示的圖片,然後onDraw方法不斷將新的畫畫出來。例項程式碼如下:
MainActivity:
public class MainActivity extends Activity { private GifView gv; private ListView lv_content; private int[] gifResource={R.drawable.car,R.drawable.rick,R.drawable.car,R.drawable.mm,R.drawable.qq}; private MyAdapter adapter=null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv_content=(ListView) findViewById(R.id.lv_content); adapter = new MyAdapter(); lv_content.setAdapter(adapter); /* lv_content.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if(adapter!=null) { adapter.notifyDataSetChanged(); } } });*/ // 去掉listView的item點選的效果 // lv_content.setEnabled(false); lv_content.setSelector(color.transparent); } private class MyAdapter extends BaseAdapter{ @Override public int getCount() { // TODO Auto-generated method stub return gifResource.length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder=null; if(convertView == null) { convertView=View.inflate(getApplicationContext(), R.layout.item_gif, null); holder=new ViewHolder(); holder.tv_username=(TextView) convertView.findViewById(R.id.tv_username); holder.tv_comemnt=(TextView) convertView.findViewById(R.id.tv_comment); holder.gv=(GifView) convertView.findViewById(R.id.gv); convertView.setTag(holder); }else{ holder=(ViewHolder) convertView.getTag(); } holder.tv_username.setText("username"+position); holder.tv_comemnt.setText("comment"+position); holder.gv.setMovieResource(gifResource[position]); holder.gv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { GifView view=(GifView) v; view.setPaused(!view.isPause()); } }); return convertView; } class ViewHolder{ public TextView tv_username; public TextView tv_comemnt; public GifView gv; } } }
自定義元件GifView:
package com.example.gifdemo.view; import com.example.gifdemo.R; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Movie; import android.os.Build; import android.os.SystemClock; import android.util.AttributeSet; import android.view.View; /**使用Android自定義的movie實現**/ public class GifView extends View{ private static final int DEFAULT_GIF_DURATION=1000; // the reference for gif private int mMovieResourceId; private Movie mMovie; private long mStart; private int mCurrentAnimationTime=0; private boolean mPause=true; private boolean mVisible=true; private long mWidth; private long mHeight; private float mScale; private float mLeft; private float mTop; private int mMeasuredWidth; private int mMeasureHeight; public GifView(Context context) { this(context,null); } public GifView(Context context, AttributeSet attrs) { this(context, attrs,R.styleable.CustomTheme_gifMoviewViewStyle); } public GifView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setViewAttributes(context, attrs, defStyleAttr); } private void setViewAttributes(Context context, AttributeSet attrs, int defStyleAttr) { /** * Starting from HONEYCOMB have to turn off HW acceleration to draw * Movie on Canvas. */ if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); } //?? TODO get the collection of the attrs final TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.GifView, defStyleAttr, R.style.Widget_GifMoviewView); mPause=array.getBoolean(R.styleable.GifView_paused, true); mMovieResourceId=array.getResourceId(R.styleable.GifView_gif, -1); // recycle TypedArray array.recycle(); if(mMovieResourceId!=-1) { mMovie=Movie.decodeStream(getResources().openRawResource(mMovieResourceId)); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if(mMovie!=null) { int mWidth=mMovie.width(); int mHeight=mMovie.height(); float scaleX=1f; int measureModeWidth=MeasureSpec.getMode(widthMeasureSpec); if(measureModeWidth!=MeasureSpec.UNSPECIFIED) { int maximumWidth=MeasureSpec.getSize(widthMeasureSpec); if(mWidth>maximumWidth) { scaleX=(float)mWidth/(float)maximumWidth; } } float scaleY=1f; int measureModeHeight=MeasureSpec.getMode(heightMeasureSpec); if(measureModeHeight!=MeasureSpec.UNSPECIFIED) { int maximumHeight=MeasureSpec.getSize(heightMeasureSpec); if(mHeight>maximumHeight) { scaleY=(float)mHeight/(float)maximumHeight; } } mScale=1f/Math.max(scaleX, scaleY); mMeasuredWidth=(int) (mWidth*mScale); mMeasureHeight=(int) (mHeight*mScale); setMeasuredDimension(mMeasuredWidth,mMeasureHeight); }else { setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight()); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); /** Calculate left / top for drawing in center **/ mLeft=(getWidth()-mMeasuredWidth)/2f; mTop=(getHeight()-mMeasureHeight)/2f; mVisible= getVisibility() == View.VISIBLE; } @Override protected void onDraw(Canvas canvas) { if(mMovie!=null) { if(!mPause) { updateCurrentTime(); drawFrame(canvas); invalidateView(); }else{ drawFrame(canvas); } } } private void updateCurrentTime() { long now=SystemClock.uptimeMillis(); if(mStart==0) { mStart=now; } int dur=mMovie.duration(); if(dur==0) { dur=DEFAULT_GIF_DURATION; } mCurrentAnimationTime=(int)((now-mStart)%dur); } private void drawFrame(Canvas canvas) { mMovie.setTime(mCurrentAnimationTime); canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.scale(mScale, mScale); // TODO mMovie.draw(canvas, mLeft/mScale, mTop/mScale); mMovie.draw(canvas, 0, 0); canvas.restore(); } /** * Invalidates view only if it is visible. * <br> * {@link #postInvalidateOnAnimation()} is used for Jelly Bean and higher. * */ @SuppressLint("NewApi") private void invalidateView() { if(mVisible) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { postInvalidateOnAnimation(); } else { invalidate(); } } } // the methods of the important attribute public void setPaused(boolean pause) { this.mPause=pause; // retrieve the StartTime if(!mPause) { mStart=SystemClock.uptimeMillis()-mCurrentAnimationTime; } invalidate(); } public boolean isPause() { return mPause; } public void setMovieResource(int movieResourceId) { this.mMovieResourceId=movieResourceId; mMovie=Movie.decodeStream(getResources().openRawResource(movieResourceId)); // important Call this when something has changed which has invalidated the //layout of this view. requestLayout(); } public void setMovie(Movie movie) { this.mMovie=movie; requestLayout(); } public Movie getMovie() { return mMovie; } public void setMovieTime(int time) { this.mCurrentAnimationTime=time; invalidate(); } }
(2)自定義TextView顯示Gif,先使用GifDecoder將Gif檔案解析成一張張圖片,然後通過ImageSpan將圖片顯示在TextView中,定義一個執行緒不斷重新整理圖片。
自定義TextView:
package com.yyg.gifdemo3.view;
public class MyTextView extends TextView{
private Context mContext;
private SpannableStringBuilder mSb=new SpannableStringBuilder();
private String dummyStr="dummy";
private SimpleImageMemCache mCache;
private List<AnimatedImageSpan> mGifSpanList=new ArrayList<AnimatedImageSpan>();
public MyTextView(Context context) {
super(context);
mContext=context;
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext=context;
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext=context;
}
public void setImageCache(SimpleImageMemCache pImageCache)
{
this.mCache=pImageCache;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.d(this.getClass().getName(), "onDetachedFromWindow ");
for (AnimatedImageSpan ais : mGifSpanList) {
Log.d(this.getClass().getName(), "animation playing " + ais.isPlaying());
if (ais.isPlaying()) {
ais.stopRendering();
}
}
mGifSpanList.clear();
mSb.clearSpans();
mSb.clear();
}
public void appendText(String text)
{
mSb.append(text);
}
public void appendAnimation(GifResource pAssetsSet,AnimationSettings pSettings)
{
mSb.append(dummyStr);
AnimatedImageSpan ais=new AnimatedImageSpan(mContext);
ais.setAssetsSet(pAssetsSet);
ais.setBitmapCache(mCache);
mSb.setSpan(ais, mSb.length()-dummyStr.length(), mSb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
AnimationClickableSpan clickableSpan=new AnimationClickableSpan(this, ais, pSettings);
mSb.setSpan(clickableSpan, mSb.length()-dummyStr.length(), mSb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mGifSpanList.add(ais);
}
public void finishAddContent()
{
this.setText(mSb);
// setMovementMethod,此方法在需要響應使用者事件時使用,如點選一個電話號碼就跳轉到撥號頁面。如果不執行這個方法是不會響應事件的,即便文字看著已經是下劃線藍色字了。
this.setMovementMethod(LinkMovementMethod.getInstance());
}
private static class AnimationClickableSpan extends ClickableSpan
{
private AnimatedImageSpan mImageSpan;
private AnimationSettings mSettings;
private AnimatedImageUpdateHandler updateHandler;
public AnimationClickableSpan(MyTextView pTextView ,AnimatedImageSpan pAnimatedImageSpan,AnimationSettings pSettings)
{
this.mImageSpan=pAnimatedImageSpan;
this.mSettings=pSettings;
this.updateHandler=new AnimatedImageUpdateHandler(pTextView);
}
@Override
public void onClick(View widget) {
if(this.mImageSpan.isPlaying())
{
this.mImageSpan.stopRendering();
}else{
this.mImageSpan.playGif(this.mSettings,this.updateHandler);
}
}
}
}
(3)使用WebView載入Gif:
package com.example.gifdemo3;
import android.os.Build;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.webkit.WebView;
public class MainActivity extends Activity {
private WebView wv_gif;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wv_gif=(WebView) findViewById(R.id.wv_gif);
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT)
{
wv_gif.loadUrl("http://www.wyzu.cn/data/uploadfile/200803/2008032812262650.gif");
}
}
}