用Movie显示gif(2)GifView

 

1,类

复制代码
  1 import android.annotation.SuppressLint;
  2 import android.content.Context;
  3 import android.content.res.TypedArray;
  4 import android.graphics.Canvas;
  5 import android.graphics.Movie;
  6 import android.os.Build;
  7 import android.util.AttributeSet;
  8 import android.view.View;
  9 
 10 import com.e.weixin.R;
 11 
 12 public class GifView extends View {
 13 
 14     /**
 15      * 默认为1秒
 16      */
 17     private static final int DEFAULT_MOVIE_DURATION = 1000;
 18 
 19     private int mMovieResourceId;   //要显示的gif的id
 20 
 21     private Movie mMovie;           //用于播放gif等
 22 
 23     private long mMovieStart;       //
 24 
 25     private int mCurrentAnimationTime = 0;
 26 
 27     private float mLeft;
 28 
 29     private float mTop;
 30 
 31     private float mScale;
 32 
 33     private int mMeasuredMovieWidth;
 34 
 35     private int mMeasuredMovieHeight;
 36 
 37     private boolean mVisible = true;
 38 
 39     private volatile boolean mPaused = false;
 40 
 41     public GifView(Context context) {
 42         this(context, null);
 43     }
 44 
 45     public GifView(Context context, AttributeSet attrs) {
 46         this(context, attrs, R.styleable.CustomTheme_gifViewStyle);
 47 //        super(context, attrs);
 48     }
 49 
 50     public GifView(Context context, AttributeSet attrs, int defStyle) {
 51         super(context, attrs, defStyle);
 52         setViewAttributes(context, attrs, defStyle);
 53     }
 54 
 55     @SuppressLint("NewApi")
 56     private void setViewAttributes(Context context, AttributeSet attrs,int defStyle) {
 57         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
 58             setLayerType(View.LAYER_TYPE_SOFTWARE, null);
 59         }
 60         // 从描述文件中读出gif的值,创建出Movie实例
 61         final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.GifView, defStyle,
 62                 R.style.Theme_GifView);
 63         mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);
 64         mPaused = array.getBoolean(R.styleable.GifView_paused, false);
 65         array.recycle();
 66         if (mMovieResourceId != -1) {
 67             mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
 68         }
 69     }
 70 
 71     /**
 72      * 设置gif图资源
 73      *
 74      * @param movieResId
 75      */
 76     public void setMovieResource(int movieResId) {
 77         this.mMovieResourceId = movieResId;
 78         mMovie = Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
 79         requestLayout();
 80     }
 81 
 82     public void setMovie(Movie movie) {
 83         this.mMovie = movie;
 84         requestLayout();
 85     }
 86 
 87     public Movie getMovie() {
 88         return mMovie;
 89     }
 90 
 91     public void setMovieTime(int time) {
 92         mCurrentAnimationTime = time;
 93         invalidate();
 94     }
 95 
 96     /**
 97      * 设置暂停
 98      *
 99      * @param paused
100      */
101     public void setPaused(boolean paused) {
102         this.mPaused = paused;
103         if (!paused) {
104             mMovieStart = android.os.SystemClock.uptimeMillis() - mCurrentAnimationTime;
105         }
106         invalidate();
107     }
108 
109     /**
110      * 判断gif图是否停止了
111      *
112      * @return
113      */
114     public boolean isPaused() {
115         return this.mPaused;
116     }
117 
118     @Override
119     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
120         if (mMovie != null) {
121             int movieWidth = mMovie.width();
122             int movieHeight = mMovie.height();
123             int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
124             float scaleW = (float) movieWidth / (float) maximumWidth;
125             mScale = 1f / scaleW;
126             mMeasuredMovieWidth = maximumWidth;
127             mMeasuredMovieHeight = (int) (movieHeight * mScale);
128             setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight);
129         } else {
130             setMeasuredDimension(getSuggestedMinimumWidth(),getSuggestedMinimumHeight());
131         }
132     }
133 
134     @Override
135     protected void onLayout(boolean changed, int l, int t, int r, int b) {
136         super.onLayout(changed, l, t, r, b);
137         mLeft = (getWidth() - mMeasuredMovieWidth) / 2f;
138         mTop = (getHeight() - mMeasuredMovieHeight) / 2f;
139         mVisible = getVisibility() == View.VISIBLE;
140     }
141 
142     @Override
143     protected void onDraw(Canvas canvas) {
144         if (mMovie != null) {
145             if (!mPaused) {
146                 updateAnimationTime();
147                 drawMovieFrame(canvas);
148                 invalidateView();
149             } else {
150                 drawMovieFrame(canvas);
151             }
152         }
153     }
154 
155     @SuppressLint("NewApi")
156     private void invalidateView() {
157         if (mVisible) {
158             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
159                 postInvalidateOnAnimation();
160             } else {
161                 invalidate();
162             }
163         }
164     }
165 
166     private void updateAnimationTime() {
167         long now = android.os.SystemClock.uptimeMillis();
168         // 如果第一帧,记录起始时间
169         if (mMovieStart == 0) {
170             mMovieStart = now;
171         }
172         // 取出动画的时长
173         int dur = mMovie.duration();
174         if (dur == 0) {
175             dur = DEFAULT_MOVIE_DURATION;
176         }
177         // 算出需要显示第几帧
178         mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
179     }
180 
181     private void drawMovieFrame(Canvas canvas) {
182         // 设置要显示的帧,绘制即可
183         mMovie.setTime(mCurrentAnimationTime);
184         canvas.save(Canvas.MATRIX_SAVE_FLAG);
185         canvas.scale(mScale, mScale);
186         mMovie.draw(canvas, mLeft / mScale, mTop / mScale);
187         canvas.restore();
188     }
189 
190     @SuppressLint("NewApi")
191     @Override
192     public void onScreenStateChanged(int screenState) {
193         super.onScreenStateChanged(screenState);
194         mVisible = screenState == SCREEN_STATE_ON;
195         invalidateView();
196     }
197 
198     @SuppressLint("NewApi")
199     @Override
200     protected void onVisibilityChanged(View changedView, int visibility) {
201         super.onVisibilityChanged(changedView, visibility);
202         mVisible = visibility == View.VISIBLE;
203         invalidateView();
204     }
205 
206     @Override
207     protected void onWindowVisibilityChanged(int visibility) {
208         super.onWindowVisibilityChanged(visibility);
209         mVisible = visibility == View.VISIBLE;
210         invalidateView();
211     }
212 }
复制代码

 

2,自定义view的属性

复制代码
 1 <resources>
 2 
 3     <declare-styleable name="GifView">
 4         <attr name="gif" format="reference" />
 5         <attr name="paused" format="boolean" />
 6     </declare-styleable>
 7     <declare-styleable name="CustomTheme">
 8         <attr name="gifViewStyle" format="reference" />
 9     </declare-styleable>
10 
11 </resources>
复制代码

 

3,使用到的主题

1     <style name="Theme.GifView" parent="@android:style/Theme.Dialog">
2         <!--...-->
3     </style>

  不用非继承 @android:style/Theme.Dialog 不可,其它主题也可以。

 

posted @   f9q  阅读(442)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示