您的位置:首页 > 移动开发 > Android开发

Android 显示 Gif动态图片的三种常用方法

2015-02-10 17:43 501 查看
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.
*
*/
@Suppres
bede
sLint("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);
}
}

}

}


完整项目链接:http://download.csdn.net/detail/aehaojiu/8438351

(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");
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android GIF TextView