SurfaceView的简单使用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SurfaceView的简单使用相关的知识,希望对你有一定的参考价值。
参考技术A public class MainActivity extends AppCompatActivity implements View.OnClickListenerprotected Button mBufferBtn;
protected Button mVideoBtn;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_main);
initView();
@Override
public void onClick(View view)
Intent intent = new Intent();
if (view.getId() == R.id.button)
intent.setClass(this, BufferActivity.class);
else if (view.getId() == R.id.button)
intent.setClass(this, VideoActivity.class);
startActivity(intent);
private void initView()
mBufferBtn = (Button) findViewById(R.id.button2);
mBufferBtn.setOnClickListener(MainActivity.this);
mVideoBtn = (Button) findViewById(R.id.button2);
mVideoBtn.setOnClickListener(MainActivity.this);
public class BufferActivity extends AppCompatActivity implements SurfaceHolder.Callback
protected SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_buffer);
initView();
initSurfaceHolder();
// 初始化Surface的管理者
private void initSurfaceHolder()
mHolder = mSurfaceView.getHolder();
// 添加管理生命周期的接口回调
mHolder.addCallback(this);
private void initView()
mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
// 缓冲区创建
@Override
public void surfaceCreated(SurfaceHolder holder)
Log.d("1507", "surfaceCreated");
new DrawThread().start();
// 缓冲区内容改变(子线程渲染UI的过程)
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
Log.d("1507", "surfaceChanged");
// 缓冲区销毁
@Override
public void surfaceDestroyed(SurfaceHolder holder)
Log.d("1507", "surfaceDestroyed");
// 绘制UI的子线程
private class DrawThread extends Thread
@Override
public void run()
super.run();
// 创建画笔
Paint paint = new Paint();
paint.setColor(Color.GREEN);// 画笔颜色
paint.setStrokeWidth(10);// 画笔粗细。注意:Java中设置的尺寸单位都是px
paint.setStyle(Paint.Style.FILL_AND_STROKE);// 设置实心
paint.setAntiAlias(true);// 设置是否抗锯齿
// 获取SurfaceView的盖度
int height = mSurfaceView.getHeight();
Canvas canvas = null;
for (int i = 0; i < height; i+= 5)
// 获取Surface中的画布
canvas = mHolder.lockCanvas();// 锁定画布
// 使用画笔在画布上绘制指定形状
canvas.drawCircle(100, i + 50, 50, paint);// 圆心x坐标,圆心y坐标,半径,画笔
// 缓冲区的画布绘制完毕,需要解锁并提交给窗口展示
mHolder.unlockCanvasAndPost(canvas);
// try
// Thread.sleep(100);
// catch (InterruptedException e)
// e.printStackTrace();
//
public class VideoActivity extends AppCompatActivity implements View.OnClickListener
protected MyVideoSurfaceView mSurfaceView;
protected Button mPlayBtn;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_video);
initView();
// 运行、可见
@Override
protected void onStart()
super.onStart();
// 可交互
@Override
protected void onResume()
super.onResume();
private void play()
String videoPath = Environment.getExternalStorageDirectory().getPath() +
"/VID_20171117_144736.3gp";// 外部存储根路径
mSurfaceView.playVideo(videoPath);
private void initView()
mSurfaceView = (MyVideoSurfaceView) findViewById(R.id.surface_view);
mPlayBtn = (Button) findViewById(R.id.play_btn);
mPlayBtn.setOnClickListener(VideoActivity.this);
@Override
public void onClick(View view)
if (view.getId() == R.id.play_btn)
play();
public class MyVideoSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private SurfaceHolder mHolder;
private MediaPlayer mMediaPlayer;
public MyVideoSurfaceView(Context context, AttributeSet attrs)
super(context, attrs);
init();
private void init()
// 获取Surface换朝哪个区的持有者
mHolder = getHolder();
mHolder.addCallback(this);
// 设置播放源
public void playVideo(String path)
if (mMediaPlayer == null)
mMediaPlayer = new MediaPlayer();
try
// 设置播放源
mMediaPlayer.setDataSource(path);
// 设置多媒体的显示部分:使用SurfaceHolder渲染画面
mMediaPlayer.setDisplay(mHolder);
mMediaPlayer.prepare();
mMediaPlayer.start();
catch (IOException e)
e.printStackTrace();
@Override
public void surfaceCreated(SurfaceHolder holder)
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
@Override
public void surfaceDestroyed(SurfaceHolder holder)
mMediaPlayer.release();
mMediaPlayer = null;
Android自定义SurfaceView简单实现烟花效果
烟花效果
实现原理
- SurfaceView + HandlerThread
为什么使用SurfaceView?
因为SurfaceView在子线程刷新不会阻塞主线程,适用于界面频繁更新、对帧率要求较高的情况,SurfaceView可以控制刷新频率,比如10ms刷新一次,SurfaceView底层利用双缓存机制,绘图时不会出现闪烁问题。 - ValueAnimator控制位移、缩放和透明度
总的来说,非常简单就能实现,利用ValueAnimator属性动画控制两张图片的位移、缩放和透明度变化,将这些动画效果组合起来就行了,直接贴代码。
代码实现
public class FireworkShow extends SurfaceView implements SurfaceHolder.Callback
private DrawTask mDrawTask; //绘制UI线程
private DrawView mLauncherView; //烟花爆炸的引信
private DrawView mFirework; //爆炸的烟花
private int mWidth; //控件宽度
private int mHeight; //控件高度
private Paint mPaint;
private int top; //引信上升的位移
private int lx, ly; //引信消失的位置
private ValueAnimator mLauncherRiseAnimator; //引信上升效果
private ValueAnimator mLauncherAlphaAnimator; //引信消失效果
private ValueAnimator mBoomAnimator; //烟花爆炸效果
private ValueAnimator mBoomEndAnimator; //烟花爆炸消失效果
private boolean isDisappear = true; //烟花是否消失
private static final int MSG_DRAW = 1;
//获取Looper
private static final HandlerThread mHandlerThread = new HandlerThread(FireworkShow.class.getName());
static
mHandlerThread.start();
//Handler消息处理
private final Handler.Callback mCallback = new Handler.Callback()
@Override
public boolean handleMessage(@NonNull Message message)
if (message.what == MSG_DRAW)
mHandler.post(mDrawTask);
mHandler.sendEmptyMessageDelayed(MSG_DRAW, 10);
return true;
;
//用Looper创建弱引用Handler
private final WeakHandler mHandler = new WeakHandler(mCallback, mHandlerThread.getLooper());
private static class WeakHandler extends Handler
private final WeakReference<Callback> mWeakReference;
public WeakHandler(Callback callback, Looper looper)
super(looper);
mWeakReference = new WeakReference<>(callback);
@Override
public void handleMessage(@NonNull Message msg)
Callback mCallback = mWeakReference.get();
if (mCallback != null)
mCallback.handleMessage(msg);
public FireworkShow(Context context)
this(context, null);
public FireworkShow(Context context, AttributeSet attributeSet)
super(context, attributeSet);
init();
private void init()
SurfaceHolder holder = getHolder();
holder.addCallback(this);
holder.setKeepScreenOn(true);
holder.setFormat(PixelFormat.TRANSPARENT);
mPaint = new Paint();
@Override
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder)
if (mDrawTask == null)
mDrawTask = new DrawTask(surfaceHolder, this);
@Override
public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int format, int width, int height)
this.mWidth = width;
this.mHeight = height;
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder)
@Override
public void draw(Canvas canvas)
if (canvas == null) return;
super.draw(canvas);
//清空界面
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
if (mLauncherView == null || mFirework == null) return;
mLauncherView.top = mHeight - mLauncherView.bitmap.getHeight() - top;
mLauncherView.left = (mWidth - mLauncherView.bitmap.getWidth()) / 2;
mPaint.setAlpha(mLauncherView.alpha);
canvas.drawBitmap(mLauncherView.bitmap, mLauncherView.left, mLauncherView.top, mPaint);
canvas.save();
mPaint.setAlpha(mFirework.alpha);
mFirework.left = (int) (lx - mFirework.bitmap.getWidth() * mFirework.scale / 2.0f);
mFirework.top = (int) (ly - mFirework.bitmap.getHeight() * mFirework.scale / 2.0f);
canvas.scale(mFirework.scale, mFirework.scale, mFirework.left, mFirework.top);
canvas.drawBitmap(mFirework.bitmap, mFirework.left, mFirework.top, mPaint);
canvas.restore();
public void startFireworkShow()
mHandler.sendEmptyMessage(MSG_DRAW);
initDrawView();
//开始动画效果
mLauncherRiseAnimator.start();
public void stopFireworkShow()
mHandler.removeMessages(MSG_DRAW);
mLauncherRiseAnimator.cancel();
mLauncherAlphaAnimator.cancel();
mBoomAnimator.cancel();
mBoomEndAnimator.cancel();
private void initDrawView()
mLauncherView = new DrawView();
mLauncherView.bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.launcher);
mFirework = new DrawView();
mFirework.bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.firework);
mLauncherRiseAnimator = ValueAnimator.ofInt(0, 1400);
mLauncherRiseAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mLauncherRiseAnimator.setDuration(4000);
mLauncherRiseAnimator.addUpdateListener(valueAnimator -> top = (int) valueAnimator.getAnimatedValue());
mLauncherRiseAnimator.addListener(new Animator.AnimatorListener()
@Override
public void onAnimationStart(Animator animator)
isDisappear = false;
//烟花不显示
mFirework.alpha = 0;
//引信发射
mLauncherView.alpha = 255;
mLauncherAlphaAnimator.start();
@Override
public void onAnimationEnd(Animator animator)
//记录引信消失的位置
lx = mLauncherView.left;
ly = mLauncherView.top;
@Override
public void onAnimationCancel(Animator animator)
@Override
public void onAnimationRepeat(Animator animator)
);
mLauncherAlphaAnimator = ValueAnimator.ofInt(255, 50);
mLauncherAlphaAnimator.setInterpolator(new LinearInterpolator());
mLauncherAlphaAnimator.setDuration(4000);
mLauncherAlphaAnimator.addUpdateListener(valueAnimator -> mLauncherView.alpha = (int) valueAnimator.getAnimatedValue());
mLauncherAlphaAnimator.addListener(new Animator.AnimatorListener()
@Override
public void onAnimationStart(Animator animator)
@Override
public void onAnimationEnd(Animator animator)
mLauncherView.alpha = 0; //引信消失
//烟花显示
mBoomAnimator.start();
@Override
public void onAnimationCancel(Animator animator)
@Override
public void onAnimationRepeat(Animator animator)
);
mBoomAnimator = ValueAnimator.ofFloat(0.0f, 2.0f);
mBoomAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mBoomAnimator.setDuration(2000);
mBoomAnimator.setStartDelay(1000);
mBoomAnimator.addUpdateListener(valueAnimator -> mFirework.scale = (float) valueAnimator.getAnimatedValue());
mBoomAnimator.addListener(new Animator.AnimatorListener()
@Override
public void onAnimationStart(Animator animator)
//烟花消失效果
mBoomEndAnimator.start();
@Override
public void onAnimationEnd(Animator animator)
@Override
public void onAnimationCancel(Animator animator)
@Override
public void onAnimationRepeat(Animator animator)
);
mBoomEndAnimator = ValueAnimator.ofInt(255, 0);
mBoomAnimator.setInterpolator(new DecelerateInterpolator());
mBoomEndAnimator.setDuration(7000);
mBoomEndAnimator.addUpdateListener(valueAnimator -> mFirework.alpha = (int) valueAnimator.getAnimatedValue());
mBoomEndAnimator.addListener(new Animator.AnimatorListener()
@Override
public void onAnimationStart(Animator animator)
@Override
public void onAnimationEnd(Animator animator)
isDisappear = true;
@Override
public void onAnimationCancel(Animator animator)
@Override
public void onAnimationRepeat(Animator animator)
);
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event)
if (isDisappear) mLauncherRiseAnimator.start();
return true;
//绘制元素
private static class DrawView
int top;
int left;
Bitmap bitmap;
float scale;
int alpha;
//绘制子线程
private static class DrawTask implements Runnable
private final SurfaceHolder holder;
private final FireworkShow fireworkShow;
public DrawTask(SurfaceHolder holder, FireworkShow fireworkShow)
this.holder = holder;
this.fireworkShow = fireworkShow;
@Override
public void run()
Canvas canvas = null;
try
canvas = holder.lockCanvas();
synchronized (holder)
fireworkShow.draw(canvas);
finally
if (canvas != null)
holder.unlockCanvasAndPost(canvas);
activity_main.xml引用:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.jon.firework.widget.FireworkShow
android:id="@+id/fs"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity使用:
public class MainActivity extends AppCompatActivity
private FireworkShow fs;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fs = findViewById(R.id.fs);
fs.startFireworkShow();
@Override
protected void onDestroy()
super.onDestroy();
fs.stopFireworkShow();
以上是关于SurfaceView的简单使用的主要内容,如果未能解决你的问题,请参考以下文章