http://blog.csdn.net/riyuegonghe/article/details/9283479
http://weavora.com/blog/2012/02/07/android-how-to-use-animated-gif/
To date Android platform supports a sufficiently large number of media formats. See documentation here. Among the declared graphic formats you’ll find the one we are interested – GIF. Generally speaking this format does not cause any difficulties until you’ll try to use a GIF file with animation. In this case, the standard class ImageViewdisplays GIF file as a usual static image. Doing search you can find forums stating that Android platform doesn’t fully support GIF, that animated GIF files cannot be used. Nevertheless you can still solve this problem and I’ll show you how.
There are at least two ways:
It is difficult to say which solution is better, however there is one important point. Although WebView is a part of any Android SDK, the ability to play animated GIF files only appeared from version Android 2.2 (API level 8). So if you plan support for vide range of devices, then second option is likely more acceptable for you. I’ll further focus on it.
It is not quite fair to say that class Movie is well documented. Otherwise, this article probably would be useless :-) So, let’s try to create a separate component that can play animated GIF files using class Movie.
OK, creating a new class GIFView, inherited from View:
1234567891011121314151617181920 |
package
com
.
wvr
.
widget
;
import
android.content.Context
;
import
android.util.AttributeSet
;
import
android.view.View
;
public
class
GIFView
extends
View
{
public
GIFView
(
Context
context
)
{
super
(
context
);
}
public
GIFView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
}
public
GIFView
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
}
}
|
Now let’s add new variable of type Movie to our class and initialize it
1234567891011121314151617181920212223242526272829303132333435 |
package
com
.
wvr
.
widget
;
import
java.io.InputStream
;
import
com.wvr.example.R
;
import
android.content.Context
;
import
android.graphics.Movie
;
import
android.util.AttributeSet
;
import
android.view.View
;
public
class
GIFView
extends
View
{
private
Movie
mMovie
;
public
GIFView
(
Context
context
)
{
super
(
context
);
initializeView
();
}
public
GIFView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
initializeView
();
}
public
GIFView
(
Context
context
,
AttributeSet
attrs
,
int
defStyle
)
{
super
(
context
,
attrs
,
defStyle
);
initializeView
();
}
private
void
initializeView
()
{
//R.drawable.loader - our animated GIF
InputStream
is
=
getContext
().
getResources
().
openRawResource
(
R
.
drawable
.
loader
);
mMovie
=
Movie
.
decodeStream
(
is
);
}
}
|
OK, now Movie object is initialized and we just need to draw it. We will use onDraw(Canvas) method for this purpose, but before that, we must let Movie object know what exact part of GIF file it should draw. To do this we need a separate variable movieStart of long type, which we assign SystemClock.uptimeMillis() value. In this case we will know when the movie was started and can calculate how much time has passed.
123456789101112131415 |
@Override
protected
void
onDraw
(
Canvas
canvas
)
{
canvas
.
drawColor
(
Color
.
TRANSPARENT
);
super
.
onDraw
(
canvas
);
long
now
=
android
.
os
.
SystemClock
.
uptimeMillis
();
if
(
movieStart
==
0
)
{
movieStart
=
now
;
}
if
(
movie
!=
null
)
{
int
relTime
=
(
int
)
((
now
-
movieStart
)
%
movie
.
duration
());
movie
.
setTime
(
relTime
);
movie
.
draw
(
canvas
,
getWidth
()
-
movie
.
width
(),
getHeight
()
-
movie
.
height
());
this
.
invalidate
();
}
}
|
All we need now is initialize GIFView in our Activity class
12345678 |
public
class
AnimatedGIFActivity
extends
Activity
{
@Override
public
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
GIFView
gifView
=
new
GIFView
(
this
);
setContentView
(
gifView
);
}
}
|
Now let’s add the possibility to pass GIF id as a parameter
12345678910111213141516171819 |
private
int
gifId
;
public
void
setGIFResource
(
int
resId
)
{
this
.
gifId
=
resId
;
initializeView
();
}
public
int
getGIFResource
()
{
return
this
.
gifId
;
}
private
void
initializeView
()
{
if
(
gifId
!=
0
)
{
InputStream
is
=
getContext
().
getResources
().
openRawResource
(
gifId
);
movie
=
Movie
.
decodeStream
(
is
);
movieStart
=
0
;
this
.
invalidate
();
}
}
|
Here is how the Activity class should look:
123456 |
public
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
GIFView
gifView
=
new
GIFView
(
this
);
gifView
.
setGIFResource
(
R
.
drawable
.
loader
);
setContentView
(
gifView
);
}
|
Another good practice is using components in XML markup. So, let’s also do this. For this purpose I’ll create fileattrs.xml (res/values/attrs.xml) with the following structure:
12345 |
<resources>
<declare-styleable
name=
"GIFView"
>
<attr
name=
"src"
format=
"reference"
/>
</declare-styleable>
</resources>
|
Now we just need to read XML-attributes in our GIFView class:
12345678910 |
private
void
setAttrs
(
AttributeSet
attrs
)
{
if
(
attrs
!=
null
)
{
TypedArray
a
=
getContext
().
obtainStyledAttributes
(
attrs
,
R
.
styleable
.
GIFView
,
0
,
0
);
String
gifSource
=
a
.
getString
(
R
.
styleable
.
GIFView_src
);
//little workaround here. Who knows better approach on how to easily get resource id - please share
String
sourceName
=
Uri
.
parse
(
gifSource
).
getLastPathSegment
().
replace
(
".gif"
,
""
);
setGIFResource
(
getResources
().
getIdentifier
(
sourceName
,
"drawable"
,
getContext
().
getPackageName
()));
a
.
recycle
();
}
}
|
After this we are able to use GIFView in XML markup the following way:
main.xml
123456789101112 |
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:components=
"http://schemas.android.com/apk/res/com.wvr.example"
android:layout_width=
"fill_parent"
android:layout_height=
"fill_parent"
android:orientation=
"vertical"
>
<com.wvr.widget.GIFView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
components:src=
"@drawable/loader"
/>
</LinearLayout>
|
Our Activity class looks the following way:
1234567 |
public
class
AnimatedGIFActivity
extends
Activity
{
@Override
public
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
main
);
}
}
|
That’s it. Have you ever used such approach or maybe you have some better solution – please let us know.