Android播放gif动画,增加屏幕掉金币效果
前言:播放gif的版本有很多,我这边使用Android自带的Movie类播放gif动画,也是在别人的基础上进行修改.有同样需求的朋友可以参考我的demo.
1.效果图如下:
2.部分主要代码
MainActivity.java 给封装的GifView设置背景gif图片资源, 绘制金币,同时开启金币屏幕掉下来的效果,监听gif播放完毕动画,结束掉金币的动画
public class MainActivity extends Activity implements OnClickListener {
private FlakeView flakeView;//金币掉落动画的主体动画
private GifView imageView;
private Button button_stop1;
private PopupWindow pop; //---------------------------------------------------------------------------------------------
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); button_stop1=(Button) findViewById(R.id.button_stop1);
imageView=(GifView) findViewById(R.id.imageView); imageView.setMovieResource(R.raw.icon_thank_lord_longen); // 设置背景gif图片资源 flakeView = new FlakeView(this);
final LinearLayout container = (LinearLayout) findViewById(R.id.container);
container.addView(flakeView); //将flakeView 添加到布局中
flakeView.addFlakes(50);//设置同时出现在屏幕上的金币数量 建议64以内 过多会引起卡顿 /**
* 绘制的类型
* @see View.LAYER_TYPE_HARDWARE
* @see View.LAYER_TYPE_SOFTWARE
* @see View.LAYER_TYPE_NONE
*/
flakeView.setLayerType(View.LAYER_TYPE_NONE, null);
pop = new PopupWindow(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
pop.setOutsideTouchable(true);
pop.setFocusable(true);
pop.showAtLocation(container,Gravity.CENTER,0,0);
MediaPlayer player = MediaPlayer.create(this, R.raw.shake);
player.start(); imageView.setOnGifPlayListener(new GifPlayListener(){
@Override
public void playFinish(){
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
pop.dismiss();
container.removeAllViews();
Toast.makeText(MainActivity.this,"播放完成", 0).show();
}
}, 500);
}
});
button_stop1.setOnClickListener(this);
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button_stop1:
if (imageView.isPaused()) {
imageView.setPaused(false);
}else {
imageView.setPaused(true);
}
break;
}
}
}
GifView.java 播放gif动画的自定义View
public class GifView extends View {
private static final int DEFAULT_MOVIE_DURATION = 1000;//默认为1秒
private GifPlayListener gifPlayListener; private int mMovieResourceId;
private Movie mMovie;
private long mMovieStart;
private int mCurrentAnimationTime = 0;
private float mLeft;
private float mTop;
private float mScale;
private int mMeasuredMovieWidth;
private int mMeasuredMovieHeight;
private boolean mVisible = true;
private volatile boolean mPaused = false; private int duration; public GifView(Context context) {
this(context, null);
} public GifView(Context context, AttributeSet attrs) {
this(context, attrs, R.styleable.CustomTheme_gifViewStyle);
} public GifView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setViewAttributes(context, attrs, defStyle);
} @SuppressLint("NewApi")
private void setViewAttributes(Context context, AttributeSet attrs,int defStyle) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
// 从描述文件中读出gif的值,创建出Movie实例
final TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.GifView, defStyle, /*R.style.Widget_GifView*/0);
mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);
mPaused = array.getBoolean(R.styleable.GifView_paused, false);
array.recycle();
if (mMovieResourceId != -1) {
mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
}
} /**
* 设置gif图资源
*
* @param movieResId
*/
public void setMovieResource(int movieResId) {
this.mMovieResourceId = movieResId;
mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
duration = mMovie.duration();//取出动画的时长
if (duration == 0) {
duration = DEFAULT_MOVIE_DURATION;
}
requestLayout();
} public void setMovie(Movie movie) {
this.mMovie = movie;
requestLayout();
} public Movie getMovie() {
return mMovie;
} public void setMovieTime(int time) {
mCurrentAnimationTime = time;
invalidate();
} /**
* 设置暂停
* @param paused
*/
public void setPaused(boolean paused) {
this.mPaused = paused;
if (!paused) {
mMovieStart = android.os.SystemClock.uptimeMillis() - mCurrentAnimationTime;
}
invalidate();
} /**
* 判断gif图是否停止了
* @return
*/
public boolean isPaused() {
return this.mPaused;
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mMovie != null) {
int movieWidth = mMovie.width();
int movieHeight = mMovie.height();
int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
float scaleW = (float) movieWidth / (float) maximumWidth;
mScale = 1f / scaleW;
mMeasuredMovieWidth = maximumWidth;
mMeasuredMovieHeight = (int) (movieHeight * mScale);
setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight);
} else {
setMeasuredDimension(getSuggestedMinimumWidth(),getSuggestedMinimumHeight());
}
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mLeft = (getWidth() - mMeasuredMovieWidth) / 2f;
mTop = (getHeight() - mMeasuredMovieHeight) / 2f;
mVisible = getVisibility() == View.VISIBLE;
} @Override
protected void onDraw(Canvas canvas) {
if (mMovie != null) {
if (!mPaused){
if(updateAnimationTime()){
drawMovieFrame(canvas);
invalidateView();
}else{
if(null!=gifPlayListener){
gifPlayListener.playFinish();
}
}
} else {
drawMovieFrame(canvas);
}
}
} @SuppressLint("NewApi")
private void invalidateView() {
if (mVisible) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
postInvalidateOnAnimation();
} else {
invalidate();
}
}
} private boolean updateAnimationTime() {
long now = android.os.SystemClock.uptimeMillis(); if (mMovieStart == 0) {// 如果第一帧,记录起始时间
mMovieStart = now;
}else if((now-mMovieStart)>=duration){//动画需要结束
return false;
}
// 算出需要显示第几帧
mCurrentAnimationTime = (int) ((now - mMovieStart) % duration);
return true;
} private void drawMovieFrame(Canvas canvas) {
mMovie.setTime(mCurrentAnimationTime);// 设置要显示的帧,绘制即可
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScale, mScale);
mMovie.draw(canvas, mLeft / mScale, mTop / mScale);
canvas.restore();
} @SuppressLint("NewApi")
@Override
public void onScreenStateChanged(int screenState) {
super.onScreenStateChanged(screenState);
mVisible = screenState == SCREEN_STATE_ON;
invalidateView();
} @SuppressLint("NewApi")
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
} @Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
} public void setOnGifPlayListener(GifPlayListener gifPlayListener) {
this.gifPlayListener = gifPlayListener;
} public interface GifPlayListener{
void playFinish();
} }
Flake.java 金币的实体类
public class Flake {
float x, y;
float rotation;
float speed;
float rotationSpeed;
int width,height;
Bitmap bitmap; static HashMap<Integer, Bitmap> bitmapMap = new HashMap<Integer, Bitmap>(); static Flake createFlake(float xRange, Bitmap originalBitmap,Context Context) {
Flake flake = new Flake();
DisplayMetrics metrics = getDisplayMetrics(Context);
if (metrics.widthPixels >= 1080) {
flake.width = (int) (5 + (float) Math.random() * 80);
float hwRatio = originalBitmap.getHeight() / originalBitmap.getWidth();
flake.height = (int) (flake.width * hwRatio + 60);
} else {
flake.width = (int) (5 + (float) Math.random() * 50);
float hwRatio = originalBitmap.getHeight() / originalBitmap.getWidth();
flake.height = (int) (flake.width * hwRatio + 40); }
flake.x = (float) Math.random() * (xRange - flake.width);
flake.y = 0 - (flake.height + (float) Math.random() * flake.height);
flake.speed = 50 + (float) Math.random() * 150;
flake.rotation = (float) Math.random() * 180 - 90;
flake.rotationSpeed = (float) Math.random() * 90 - 45;
flake.bitmap = bitmapMap.get(flake.width);
if (flake.bitmap == null) {
flake.bitmap = Bitmap.createScaledBitmap(originalBitmap,(int) flake.width, (int) flake.height, true);
bitmapMap.put(flake.width,flake.bitmap);
}
return flake;
} /**
* 获取屏幕尺寸与密度.
* @param context the context
* @return mDisplayMetrics
*/
public static DisplayMetrics getDisplayMetrics(Context context) {
Resources mResources;
if (context == null) {
mResources = Resources.getSystem(); } else {
mResources = context.getResources();
}
//DisplayMetrics{density=1.5, width=480, height=854, scaledDensity=1.5, xdpi=160.421, ydpi=159.497}
//DisplayMetrics{density=2.0, width=720, height=1280, scaledDensity=2.0, xdpi=160.42105, ydpi=160.15764}
DisplayMetrics mDisplayMetrics = mResources.getDisplayMetrics();
return mDisplayMetrics;
}
}
FlakeView.java 绘制金币的View 金币屏幕掉下的动画
public class FlakeView extends View {
Bitmap droid; // The bitmap that all flakes use
int numFlakes = 0; // Current number of flakes
ArrayList<Flake> flakes = new ArrayList<Flake>(); // List of current flakes
public ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
long startTime, prevTime; // Used to track elapsed time for animations and fps
int frames = 0; // Used to track frames per second
Paint textPaint; // Used for rendering fps text
float fps = 0; // frames per second
Matrix m = new Matrix(); // Matrix used to translate/rotate each flake during rendering
String fpsString = "";
String numFlakesString = "";
/**
* Constructor. Create objects used throughout the life of the View: the Paint and
* the animator
*/
public FlakeView(Context context) {
super(context);
droid = BitmapFactory.decodeResource(getResources(), R.drawable.icon_coin);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(24); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
long nowTime = System.currentTimeMillis();
float secs = (float) (nowTime - prevTime) / 100f;
prevTime = nowTime;
for (int i = 0; i < numFlakes; ++i) {
Flake flake = flakes.get(i);
flake.y += (flake.speed * secs);
if (flake.y > getHeight()) {
flake.y = 0 - flake.height;
}
flake.rotation = flake.rotation + (flake.rotationSpeed * secs);
}
invalidate();
}
});
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setDuration(3000);
} int getNumFlakes() {
return numFlakes;
} private void setNumFlakes(int quantity) {
numFlakes = quantity;
numFlakesString = "numFlakes: " + numFlakes;
} /**
* Add the specified number of droidflakes.
*/
public void addFlakes(int quantity) {
for (int i = 0; i < quantity; ++i) {
flakes.add(Flake.createFlake(getWidth(),droid,getContext()));
}
setNumFlakes(numFlakes + quantity);
} void subtractFlakes(int quantity) {
for (int i = 0; i < quantity; ++i) {
int index = numFlakes - i - 1;
flakes.remove(index);
}
setNumFlakes(numFlakes - quantity);
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Reset list of droidflakes, then restart it with 8 flakes
flakes.clear();
numFlakes = 0;
addFlakes(16);
// Cancel animator in case it was already running
animator.cancel();
// Set up fps tracking and start the animation
startTime = System.currentTimeMillis();
prevTime = startTime;
frames = 0;
animator.start();
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < numFlakes; ++i) {
Flake flake = flakes.get(i);
m.setTranslate(-flake.width / 2, -flake.height / 2);
m.postRotate(flake.rotation);
m.postTranslate(flake.width / 2 + flake.x, flake.height / 2 + flake.y);
canvas.drawBitmap(flake.bitmap, m, null);
}
// fps counter: count how many frames we draw and once a second calculate the
// frames per second
++frames;
long nowTime = System.currentTimeMillis();
long deltaTime = nowTime - startTime;
if (deltaTime > 1000) {
float secs = (float) deltaTime / 1000f;
fps = (float) frames / secs;
// fpsString = "fps: " + fps;
startTime = nowTime;
frames = 0;
}
} public void pause() {
animator.cancel();
} public void resume() {
animator.start();
} }
activity_main.xml 布局文件
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"> <com.xx.gifdemo.GifView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:enabled="false"
android:hardwareAccelerated="false" /> <Button
android:id="@+id/button_stop1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="停止/继续"/>
</RelativeLayout> <LinearLayout
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"/> </FrameLayout>
Android播放gif动画,增加屏幕掉金币效果的更多相关文章
- Android 播放Gif 动画
在Android 中是不支持直接使用Gif 图片关联播放帧动画,如下动画在Android 中是无法播放的: Android 提供了另外一种解决的办法,就是使用AnimationDrawable 这一函 ...
- Android 播放电影时滑动屏幕调整屏幕亮度(转)
(转自:http://blog.csdn.net/piaozhiye/article/details/6544450) 发现有一些主流的播放器播放电影时可以通过滑动屏幕调整屏幕亮度,其实实现起来也很容 ...
- Android播放图片动画
1.布局文件中添加ImageView <ImageView android:id="@+id/iv_fan" android:layout_width="wrap_ ...
- Android实现播放GIF动画的强大ImageView
我个人是比较喜欢逛贴吧的,贴吧里总是会有很多搞笑的动态图片,经常看一看就会感觉欢乐很多,可以释放掉不少平时的压力.确实,比起一张单调的图片,动态图片明显更加的有意思.一般动态图片都是GIF格式的,浏览 ...
- android 通过帧动画方式播放Gif动画
注意:经过本人测试,这个方法很耗内存, 图片一多就崩了.慎用 <1>用工具(photoshop或者FireWorks)将GIF动画图片分解成多个GIF静态图片,然后保存在res\drawa ...
- Android高级控件(二)——SurfaceView实现GIF动画架包,播放GIF动画,自己实现功能的初体现
Android高级控件(二)--SurfaceView实现GIF动画架包,播放GIF动画,自己实现功能的初体现 写这个的原因呢,也是因为项目中用到了gif动画,虽然网上有很多的架包可以实现,不过我们还 ...
- android 拓展ImageView播放GIF动画
原生Android控件ImageView并不能支持播放GiF格式的图片.如果将一张GIF的图片放入ImageView中,它只会显示图片的第一帧,不会产生任何动画效果. Android中播放GIF动画实 ...
- 初识android中的动画
动画效果可以大大提高界面的交互效果,因此,动画在移动开发中的应用场景较为普遍.掌握基本的动画效果在成熟的软件开发中不可或缺.除此之外,用户对于动画的接受程度远高于文字和图片,利用动画效果可以加深用户对 ...
- Android Animation(动画)
前言 Android 平台提供实现动画的解决方案(三种) 一.3.0以前,android支持两种动画: (1)Frame Animation:顺序播放事先做好的图像,与gif图片原理类似,是一种逐帧动 ...
随机推荐
- 强制 history 不记住特定的命令
使用 HISTCONTROL 强制 history 不记住特定的命令将 HISTCONTROL 设置为 ignorespace,并在不想被记住的命令前面输入一个空格: # export HISTCON ...
- VPB和OSGGIS安装
VPB和OSGGIS安装 转自:http://blog.sina.com.cn/s/blog_668aae780101k6pr.html 第一部分VPB安装 VirtualPlanetBuilder是 ...
- JAVA实现AES 解密报错Input length must be multiple of 16 when decrypting with padded cipher
加密代码 /**解密 * @param content 待解密内容 * @param password 解密密钥 * @return */ public static byte[] decrypt(b ...
- poj3250
//(栈)poj3250将第i头牛能看到多少牛传化为第i头牛能被多少牛看见 /* #include <stdio.h> #include <stack> using names ...
- 多线程相关------临界区CriticalSection
多线程一直是短板,整理相关知识方便查询 临界区(Critical Section) 临界区是一段供线程独占式访问的代码.在任意时刻,若有一个线程正在访问该代码段,如果其他所有试图访问的线程都将被挂起, ...
- 用C#语言在Visual Studio 2010里开发一个自定义的PowerShell Cmdlet
1. 打开Visual Studio 2010 2. 新建一个基于Class Library的项目 3. 给项目起个名字然后OK 4. 为项目添加下列Reference System.Manageme ...
- DOMO1
以下是Demo首页的预览图 demo下载:http://www.eoeandroid.com/forum.php?mod=attachment&aid=NjE0Njh8ZTIyZDA2M2N8 ...
- ex1-第一个程序 ”helloworld”
代码: print("Hello world.")print("Hello again.")print("I like typing this.&qu ...
- .Net开发笔记(十五) 基于“泵”的TCP通讯(接上篇)
上一篇博客中说了基于“泵”的UDP通讯,附上了一个Demo,模拟飞鸽传书的功能,功能不太完善,主要是为了说明“泵”在编程中的应用.本篇文章我再附上一个关于TCP通讯的两个Demo,也都采用了“泵”模式 ...
- 给公司部门设计的SOA架构
新来老大年前开会说各位同学,公司业务越来越重,未来几年要成倍增长......,要梳理出一套新架构,才能更好的支持N万用户.....,以后升职加薪当上....打败..... 想想还有点小激动呢,于是过年 ...