Saya telah mengembangkan implementasi serupa untuk menguji apakah saya harus menggunakan View atau SurfaceView. Saya menerapkan Tampilan seperti di bawah ini
public class TimerView extends View {
private Paint mPiePaint;
private RectF mShadowBounds;
private float diameter;
int startCount = 0;
private PanelThread thread;
public TimerView(Context context) {
super(context);
init();
}
public TimerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TimerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(VERSION_CODES.LOLLIPOP)
public TimerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
mPiePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPiePaint.setStyle(Paint.Style.FILL);
mPiePaint.setColor(0xff000000);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Account for padding
float xpad = (float)(getPaddingLeft() + getPaddingRight());
float ypad = (float)(getPaddingTop() + getPaddingBottom());
float ww = (float)w - xpad;
float hh = (float)h - ypad;
// Figure out how big we can make the pie.
diameter = Math.min(ww, hh);
mShadowBounds = new RectF(0, 0, diameter, diameter);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (startCount == 360) startCount= 0;
canvas.drawArc(mShadowBounds,
0, startCount, true, mPiePaint);
invalidate();
startCount++;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
int w = resolveSizeAndState(minw, widthMeasureSpec, 1);
int h = resolveSizeAndState(MeasureSpec.getSize(w), heightMeasureSpec, 0);
setMeasuredDimension(w, h);
}
}
Dan saya menerapkan Surface View saya seperti di bawah ini
public class TimerSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private Paint mPiePaint;
private RectF mShadowBounds;
private float diameter;
int startCount = 0;
private PanelThread thread;
public TimerSurfaceView(Context context) {
super(context);
init();
}
public TimerSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TimerSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(VERSION_CODES.LOLLIPOP)
public TimerSurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
getHolder().addCallback(this);
mPiePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPiePaint.setStyle(Paint.Style.FILL);
mPiePaint.setColor(0xff000000);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Account for padding
float xpad = (float)(getPaddingLeft() + getPaddingRight());
float ypad = (float)(getPaddingTop() + getPaddingBottom());
float ww = (float)w - xpad;
float hh = (float)h - ypad;
// Figure out how big we can make the pie.
diameter = Math.min(ww, hh);
mShadowBounds = new RectF(0, 0, diameter, diameter);
}
protected void drawSomething(Canvas canvas) {
canvas.drawColor(0xFFEEEEEE);
if (startCount == 360) startCount= 0;
canvas.drawArc(mShadowBounds,
0, startCount, true, mPiePaint);
startCount++;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth();
int w = resolveSizeAndState(minw, widthMeasureSpec, 1);
int h = resolveSizeAndState(MeasureSpec.getSize(w), heightMeasureSpec, 0);
setMeasuredDimension(w, h);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()
thread = new PanelThread(getHolder(), this); //Start the thread that
thread.setRunning(true); //will make calls to
thread.start(); //onDraw()
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
}
Dan SurfaceView Thread seperti di bawah ini
class PanelThread extends Thread {
private SurfaceHolder surfaceHolder;
private TimerSurfaceView panel;
private boolean starRunning = false;
public PanelThread(SurfaceHolder surfaceHolder, TimerSurfaceView panel) {
this.surfaceHolder = surfaceHolder;
this.panel = panel;
}
public void setRunning(boolean run) { //Allow us to stop the thread
starRunning = run;
}
@Override
public void run() {
Canvas c;
while (starRunning) { //When setRunning(false) occurs, starRunning is
c = null; //set to false and loop ends, stopping thread
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
//Insert methods to modify positions of items in onDraw()
panel.drawSomething(c);
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
Hasilnya menunjukkan bahwa Tampilan Kustom (TimerView) lebih mulus dibandingkan Tampilan Permukaan, seperti yang ditunjukkan di https://www.youtube.com/watch?v=s9craUgY3I4 . Menurut http://stackoverflow.com/questions/23893266/why-surfaceview-is-slower-than-a-custom-view
, SurfaceView meskipun lebih lambat, seharusnya lebih lancar.
Mungkinkah karena di SurfaceView, saya perlu mewarnai ulang untuk menghapus fungsi undian canvas.drawColor(0xFFEEEEEE);
pada drawSomething
sebelumnya? Apakah ada cara untuk menghilangkan kebutuhan pewarnaan ulang, seperti yang saya lakukan di TimerView, saya hanya invalidate()
selama onDraw
?
Masalah lain yang saya hadapi adalah, ketika Aplikasi pergi ke latar belakang dan kembali, drawSomthing
dari TimerSurfaceView akan menerima Kanvas nol, sedangkan TimerView onDraw() tidak valid, dan animasi berhenti begitu saja. Adakah yang perlu saya lakukan agar hal ini tetap berlanjut seperti semula?