【问题标题】:onTouch calling invalidate onDraw - not smoothonTouch 调用无效 onDraw - 不流畅
【发布时间】:2016-04-02 03:33:18
【问题描述】:

我的自定义视图中有一个代码,如果我在其中触摸,则会绘制一个圆圈。当我移动圆圈时,请跟随。代码如下

// override onDraw
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (circleBounds != null) {
        canvas.drawArc(circleBounds, 360, 360, false, mPaint);
    }
}

// when ACTION_DOWN start touch according to the x,y values
private void startTouch(float x, float y) {
    mPath.moveTo(x, y);
    mX = x;
    mY = y;
    circleBounds.set(mX - mRadius, mY - mRadius, mX + mRadius, mY + mRadius);

    invalidate();
}


//override the onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        startTouch(x, y);
        break;
    case MotionEvent.ACTION_MOVE:
        startTouch(x, y);
        break;
    }
    return true;
}

当我缓慢移动时,移动是平稳的。但是当我快速移动时,可以感觉到闪烁。我猜 invalidate() 发生了很多次,导致闪烁。有没有办法让它更平滑(减少绘制圆圈上的闪烁)?

【问题讨论】:

  • 你的目标是什么?你可以通过其他方式来实现它。
  • 我喜欢当我触摸的时候,无论我走到哪里,圆圈都跟着我的手。它确实实现了我想做的事情。但只是觉得它没有那么光滑(轻微闪烁)。还有什么其他方法可以实现?
  • 删除mPath.moveTo(x, y);,因为你不会在任何地方使用mPath

标签: java android android-canvas android-custom-view ondraw


【解决方案1】:

我知道这个问题很老了,但如果其他人也有同样的问题,解决方案是在onTouchEvent 方法中使用postInvalidate() 而不是invalidate(),这样会更流畅。

由于我们在onTouchEvent 中收到许多事件,因此将无效调用放入事件队列以供将来处理比立即执行更有效。

【讨论】:

    【解决方案2】:

    无效不是你的问题,系统有双缓冲,你应该看不到闪烁。 从您的代码中,我可以想到两种改进方法:

    1. 在 onStartTouch 中调用 mPath.moveTo()。目前尚不清楚为什么需要 mPath,但这条路径会不断增长,并且需要更多内存
    2. canvas.drawArc 由 CPU 渲染(它创建一个位图并在每次调用 onDraw 时将弧绘制到其中)。将自己的圆圈渲染为位图并在 onDraw 中绘制该位图会更快。如果您继续使用相同的位图,它将被加载到 GPU 一次,并且绘图会更快

    【讨论】:

    • 感谢您的意见。是的,应该删除未使用的 mPath。渲染到位图是个好主意,尤其是对于复杂的绘图。我做了更改,但仍然不是很流畅,类似于drawArc轻微闪烁。但我想,我对小闪烁有点太挑剔了。当然更复杂的绘图,位图和手动绘图会有明显的区别。我打勾你的答案。谢谢!
    【解决方案3】:
    public class MyView extend FrameLayout implement OnTouchListener{
       public MyView(params){
          init();
       }
    
       private void init(){
          ImageView imageView = new ImageView();
          imageView.setImageResource(R.mipmap.logo);
          addView(imageview)
    
          imageView.setOnTouchListener(this);
       }
    
       private boolean onTouch(params){
           //some logic to control
           //use imageView.setLayoutParams() instead of invalidate();
       }
    }
    

    【讨论】:

    • 嗯...似乎与我上面的问题无关。我正在创建自定义视图,任何活动/片段都可以使用它。我没有创建活动或布局。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多