zoukankan      html  css  js  c++  java
  • 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>

    点击下载源码

  • 相关阅读:
    安卓中bitmap16进制计算
    Android Studio打包aar文件
    cmake中的link_directories, LINK_LIBRARIES, target_link_libraries的区别 Linux 下cmake生成SO库的使用实例
    win10 编译好的CPU版本caffe 配置自己的图像分类C++DEMO
    将基于Keras训练的Unet模型通过TensorFlow的C++接口部署
    关于tensorflow中转置卷积使用的理解
    将keras的h5模型转换为tensorflow的pb模型
    win10环境下pyinstaller打包pytorch遇到的问题及解决方案
    计算机网络安全 —— C# 使用谷歌身份验证器(Google Authenticator)(五)
    计算机网络安全 —— 实体鉴别与生成大随机数(四)
  • 原文地址:https://www.cnblogs.com/yishaochu/p/5078612.html
Copyright © 2011-2022 走看看