Android 如何优化画布上的绘图文本
我的窗户有三个圆圈,它们同时旋转。一切都很好,直到向圆中添加文本,然后旋转开始滞后 如何优化画布上的绘图? 这是我的代码:Android 如何优化画布上的绘图文本,android,android-canvas,Android,Android Canvas,我的窗户有三个圆圈,它们同时旋转。一切都很好,直到向圆中添加文本,然后旋转开始滞后 如何优化画布上的绘图? 这是我的代码: @Override protected void onDraw(final Canvas canvas) { if (mPaint == null) { mPaint = new Paint(); mPaint.setTextSize(20f); } drawUpperCircle(canvas);
@Override
protected void onDraw(final Canvas canvas) {
if (mPaint == null) {
mPaint = new Paint();
mPaint.setTextSize(20f);
}
drawUpperCircle(canvas);
drawBottomCircle(canvas);
drawMainCircle(canvas);
try {
Thread.sleep(1, 1);
invalidate();
mRotation += 0.9;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onDraw(canvas);
}
private void drawUpperCircle(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, 0, mUpperCircleCentr);
mPaint.setColor(Color.CYAN);
canvas.drawCircle(0, mUpperCircleCentr, mUpperCirclRadius, mPaint);
mPaint.setColor(Color.BLACK);
for (int i = 0; i < SEG_COUNT; i++) {
canvas.rotate(SEG_IN_GRAD, 0, mUpperCircleCentr);
canvas.drawLine(0, mUpperCircleCentr, mUpperCirclRadius, mUpperCircleCentr, mPaint);
// canvas.drawText("my text" + String.valueOf(i), mUpperCirclRadius * 2 / 3, mUpperCircleCentr - 4, mPaint);
}
canvas.restore();
}
private void drawBottomCircle(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, 0, mBottomCircleCentr);
mPaint.setColor(Color.RED);
canvas.drawCircle(0, mBottomCircleCentr, mBottomCirclRadius, mPaint);
mPaint.setColor(Color.BLACK);
for (int i = 0; i < SEG_COUNT; i++) {
canvas.rotate(SEG_IN_GRAD, 0, mBottomCircleCentr);
canvas.drawLine(0, mBottomCircleCentr, mBottomCirclRadius, mBottomCircleCentr, mPaint);
// canvas.drawText("my text" + String.valueOf(i), mBottomCirclRadius * 2 / 3, mBottomCircleCentr - 4, mPaint);
}
canvas.restore();
}
private void drawMainCircle(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, 0, mMainCircleCentr);
mPaint.setColor(Color.argb(100, 100, 100, 100));
canvas.drawCircle(0, mMainCircleCentr, mMainCirclRadius, mPaint);
mPaint.setColor(Color.BLACK);
for (int i = 0; i < SEG_COUNT; i++) {
canvas.rotate(SEG_IN_GRAD, 0, mMainCircleCentr);
canvas.drawLine(0, mMainCircleCentr, mMainCirclRadius, mMainCircleCentr, mPaint);
canvas.drawText("my text" + String.valueOf(i), mMainCirclRadius * 2 / 3, mMainCircleCentr - 4, mPaint);
}
canvas.restore();
}
主要工作是在DrawThread.java中完成的
公共类DrawThread扩展线程{
private ArrayList mmaincirclepath=新的ArrayList(SEG_COUNT);
私有ArrayList MupperCirclePath=新ArrayList(SEG_计数);
私有ArrayList McEnterCirclePath=新ArrayList(SEG_计数);
私有ArrayList MBotomCirclePath=新ArrayList(SEG_计数);
私有布尔值mRun=false;
私人地表持有人;
私有DrawView mDrawView;
私人油漆;
私有电路模型mCirclesModel;
公共浮点数旋转=0;
公共抽丝(SurfaceHolder SurfaceHolder、DrawView DrawView){
mSurfaceHolder=表面支架;
mDrawView=drawView;
mCirclesModel=newcirclesmodel(mDrawView.getHeight());
mPaint=新油漆(油漆.防油漆别名标志);
mPaint.setTextSize(18f);
初始化路径();
}
公共void setRunning(布尔b){
mRun=b;
}
@凌驾
公开募捐{
while(mRun){
Canvas=null;
试一试{
canvas=mSurfaceHolder.lockCanvas(null);
已同步(mSurfaceHolder){
drawMainCircle(帆布);
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mCirclesModel.mmaincorclecentr[CircleModel.X],mCirclesModel.mmaincorclecentr[CircleModel.Y],
mCirclesModel.mSmallCirclesRadius,mpain);
drawCenterCircle(画布);
drawUpperCircle(帆布);
画圈(帆布);
//旋转+=0.5f;
}
}最后{
if(canvas!=null){
mSurfaceHolder.unlockCanvasAndPost(画布);
}
}
}
}
私有void drawMainCircle(画布){
canvas.save();
旋转(mRotation,mCirclesModel.mmaincorclecentr[CirclesModel.X],mCirclesModel.mmaincorclecentr[CirclesModel.Y]);
浮动旋转=旋转;
mPaint.setColor(Color.LTGRAY/*argb(100255、255、255)*/);
canvas.drawCircle(mCirclesModel.mmaincorclecentr[CircleModel.X],mCirclesModel.mmaincorclecentr[CircleModel.Y],
mCirclesModel.mBigCirclesRadius,mPaint);
mPaint.setColor(Color.BLACK);
对于(int i=0;imCirclesModel.mMainCircleSegment[0]&&absRot
在两行代码中实现了双缓冲
canvas=mSurfaceHolder.lockCanvas(null)代码>这里我从曲面视图画布中获取,我将在其中绘制下一帧
mSurfaceHolder.解锁canvasandpost(画布)代码>这里我将SurfaceView上的当前图像与新的canwas重叠,这是图像更改的时刻。请注意,如果您有透明元素,那么前面的图像将仍然可见,图像不会被替换,而是重叠。您的代码非常漂亮和简单。您可以通过使用较少的循环来优化它,例如,将所有内容都绘制在一起或组合变量,但这很快就会变得混乱
我建议您保持图形代码大致相同。实际上,您没有做最糟糕的事情:实例化对象,而且它很清晰,易于维护
但您可以尝试使用双缓冲区:在ram中绘制缓冲区,然后在屏幕上一次性翻转缓冲区。这通常可以很好地实现恒定的动画速度。使用画布的锁定和解锁:您的代码非常漂亮和简单。您可以通过使用较少的循环来优化它,例如,将所有内容都绘制在一起或组合变量,但这很快就会变得混乱
我建议您保持图形代码大致相同。实际上,您没有做最糟糕的事情:实例化对象,而且它很清晰,易于维护
但您可以尝试使用双缓冲区:在ram中绘制缓冲区,然后在屏幕上一次性翻转缓冲区。这通常可以很好地实现恒定的动画速度。使用画布的锁定和解锁:下面是包含一些优化的代码版本
首先,我尽量不画那些目前在屏幕外的线条和文字。我通过跟踪旋转角度,跳过90到270度之间的净旋转的图形来实现这一点。在我的2.3模拟器上,总体性能提高了25%
其次,我通过初始化一个数组(ArrayList
)来“缓存”要绘制的字符串,每个字符串都有一个路径。我在您曾经初始化mpain
的同一个位置执行此操作。然后我使用canvas.drawPath(…)绘制字符串。在我的2.3模拟器上,性能又提高了33%。最终的效果是旋转速度增加了一倍左右。此外,它还阻止了文本的“摇摆”
其他一些注意事项:
我删除了线程。sleep(1,1)
。我不确定你到底想用它完成什么
我换了轮换
public class DrawView extends SurfaceView implements SurfaceHolder.Callback {
...............................................................
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float currentX = event.getX();
float currentY = event.getY();
float deltaX, deltaY;
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
// Modify rotational angles according to movement
deltaX = currentX - previousX;
deltaY = currentY - previousY;
mDrawThread.mRotation += deltaY * 180 / getHeight();
}
// Save current x, y
previousX = currentX;
previousY = currentY;
return true; // Event handled
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mDrawThread = new DrawThread(getHolder(), this);
mDrawThread.setRunning(true);
mDrawThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
boolean retry = true;
mDrawThread.setRunning(false);
while (retry) {
try {
mDrawThread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class DrawThread extends Thread {
private ArrayList<Path> mMainCirclePaths = new ArrayList<Path>(SEG_COUNT);
private ArrayList<Path> mUpperCirclePaths = new ArrayList<Path>(SEG_COUNT);
private ArrayList<Path> mCenterCirclePaths = new ArrayList<Path>(SEG_COUNT);
private ArrayList<Path> mBottomCirclePaths = new ArrayList<Path>(SEG_COUNT);
private boolean mRun = false;
private SurfaceHolder mSurfaceHolder;
private DrawView mDrawView;
private Paint mPaint;
private CirclesModel mCirclesModel;
public float mRotation = 0;
public DrawThread(SurfaceHolder surfaceHolder, DrawView drawView) {
mSurfaceHolder = surfaceHolder;
mDrawView = drawView;
mCirclesModel = new CirclesModel(mDrawView.getHeight());
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setTextSize(18f);
initPaths();
}
public void setRunning(boolean b) {
mRun = b;
}
@Override
public void run() {
while (mRun) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
drawMainCircle(canvas);
mPaint.setColor(Color.WHITE);
canvas.drawCircle(mCirclesModel.mMainCircleCentr[CirclesModel.X], mCirclesModel.mMainCircleCentr[CirclesModel.Y],
mCirclesModel.mSmallCirclesRadius, mPaint);
drawCenterCircle(canvas);
drawUpperCircle(canvas);
drawBottomCircle(canvas);
//mRotation += 0.5f;
}
} finally {
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
private void drawMainCircle(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, mCirclesModel.mMainCircleCentr[CirclesModel.X], mCirclesModel.mMainCircleCentr[CirclesModel.Y]);
float rot = mRotation;
mPaint.setColor(Color.LTGRAY/* argb(100, 255, 255, 255) */);
canvas.drawCircle(mCirclesModel.mMainCircleCentr[CirclesModel.X], mCirclesModel.mMainCircleCentr[CirclesModel.Y],
mCirclesModel.mBigCirclesRadius, mPaint);
mPaint.setColor(Color.BLACK);
for (int i = 0; i < SEG_COUNT; i++) {
canvas.rotate(SEG_IN_GRAD, mCirclesModel.mMainCircleCentr[CirclesModel.X], mCirclesModel.mMainCircleCentr[CirclesModel.Y]);
rot += SEG_IN_GRAD;
float absRot = Math.abs(rot % 360);
if (absRot > mCirclesModel.mMainCircleSegment[0] && absRot < mCirclesModel.mMainCircleSegment[1]) {
continue;
}
canvas.drawLine(mCirclesModel.mMainCircleCentr[CirclesModel.X], mCirclesModel.mMainCircleCentr[CirclesModel.Y],
mCirclesModel.mBigCirclesRadius, mCirclesModel.mMainCircleCentr[CirclesModel.Y], mPaint);
canvas.drawPath(mMainCirclePaths.get(i), mPaint);
// canvas.drawText("my text" + String.valueOf(i),
// mMainCirclRadius * 2 / 3, mMainCircleCentr - 4, mPaint);
}
canvas.restore();
}
.................................................................
}
public class AnimView extends View {
Paint mPaint;
ArrayList<Path> mTextPaths;
float mRotation = 0f;
float mUpperCircleCentr = 150f;
float mUpperCirclRadius = 150f;
private static final int SEG_COUNT = 60;
private static final float SEG_IN_GRAD = 360.0f / SEG_COUNT;
float mBottomCircleCentr = 450f;
float mBottomCirclRadius = 150f;
float mMainCircleCentr = 300f;
float mMainCirclRadius = 300f;
long mLastMillis = 0L;
// ctors removed
@Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
if (mPaint == null) {
mPaint = new Paint();
mPaint.setTextSize(20f);
// init text paths
mTextPaths = new ArrayList<Path>(SEG_COUNT);
for (int i = 0; i < SEG_COUNT; i++) {
Path path = new Path();
String s = "my text" + String.valueOf(i);
mPaint.getTextPath(s, 0, s.length(), mMainCirclRadius * 2 / 3, mMainCircleCentr - 4, path);
path.close(); // not required on 2.2/2.3 devices
mTextPaths.add(path);
}
}
if (mLastMillis == 0L) {
mLastMillis = System.currentTimeMillis();
}
drawUpperCircle(canvas);
drawBottomCircle(canvas);
drawMainCircle(canvas);
invalidate();
if (((int) mRotation) % 10 == 0) {
long millis = System.currentTimeMillis();
Log.w("AnimateCanvas", "OnDraw called with mRotation == " + mRotation);
Log.w("AnimateCanvas", "Last 10 degrees took millis: " + (millis - mLastMillis));
mLastMillis = millis;
}
}
private void drawUpperCircle(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, 0, mUpperCircleCentr);
float rot = mRotation;
mPaint.setColor(Color.CYAN);
canvas.drawCircle(0, mUpperCircleCentr, mUpperCirclRadius, mPaint);
mPaint.setColor(Color.BLACK);
for (int i = 0; i < SEG_COUNT; i++) {
canvas.rotate(SEG_IN_GRAD, 0, mUpperCircleCentr);
rot += SEG_IN_GRAD;
if (rot % 360 > 90 && rot % 360 < 270)
continue;
canvas.drawLine(0, mUpperCircleCentr, mUpperCirclRadius, mUpperCircleCentr, mPaint);
}
canvas.restore();
}
private void drawBottomCircle(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, 0, mBottomCircleCentr);
float rot = mRotation;
mPaint.setColor(Color.RED);
canvas.drawCircle(0, mBottomCircleCentr, mBottomCirclRadius, mPaint);
mPaint.setColor(Color.BLACK);
for (int i = 0; i < SEG_COUNT; i++) {
canvas.rotate(SEG_IN_GRAD, 0, mBottomCircleCentr);
rot += SEG_IN_GRAD;
if (rot % 360 > 90 && rot % 360 < 270)
continue;
canvas.drawLine(0, mBottomCircleCentr, mBottomCirclRadius, mBottomCircleCentr, mPaint);
}
canvas.restore();
}
private void drawMainCircle(Canvas canvas) {
canvas.save();
canvas.rotate(mRotation, 0, mMainCircleCentr);
float rot = mRotation;
mPaint.setColor(Color.argb(100, 100, 100, 100));
canvas.drawCircle(0, mMainCircleCentr, mMainCirclRadius, mPaint);
mPaint.setColor(Color.BLACK);
for (int i = 0; i < SEG_COUNT; i++) {
canvas.rotate(SEG_IN_GRAD, 0, mMainCircleCentr);
rot += SEG_IN_GRAD;
if (rot % 360 > 90 && rot % 360 < 270)
continue;
canvas.drawLine(0, mMainCircleCentr, mMainCirclRadius, mMainCircleCentr, mPaint);
canvas.drawPath(mTextPaths.get(i), mPaint);
// canvas.drawText("my text" + String.valueOf(i), mMainCirclRadius * 2 / 3, mMainCircleCentr - 4, mPaint);
}
canvas.restore();
}
}