Android画布,多个路径具有不同的缩放量

12

这应该是一个简单的白板工具,带有缩放/平移效果。

整个路径绘制部分都没问题,只是在缩放/平移时出现了一些问题。

当对白板进行缩放时,无论我怎么做,所有在缩放之后的线条都会相对于我实际绘制的位置发生位移。

我将尽可能详细地说明情况,不显示不必要的代码,但这是一篇相当长的文章,请耐心阅读。

因为一张图片胜过千言万语,我将用图示来说明情况:

enter image description here

enter image description here

enter image description here

enter image description here

所以,我尝试了许多不同的方法,但都没有成功。

现在进入技术部分,这是我目前正在做的:

它是通过扩展View来实现的。

我只使用onDraw方法来执行应用笔画的“动画”:

@Override
public void onDraw(Canvas canvas) 
{
    super.onDraw(canvas);

    if(isDrawing)
    {
        canvas.drawPath(mPath,  mPaint);
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);   
    }
}

我有两个ImageView,用于在绘制和缩放完成后放置生成的位图。我使用两个视图的原因是为了交换它们,以便始终在绘制渲染时有一个可用的视图。
 <ImageView
 android:id="@+id/imageView"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_alignParentLeft="true"  
 android:layout_alignParentTop="true"    
 android:visibility="visible"     
 android:scaleType="matrix" />

 <ImageView     
 android:id="@+id/imageView2"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:layout_alignParentLeft="true"          
 android:layout_alignParentTop="true"    
 android:visibility="visible"     
 android:scaleType="matrix" />

在画布上绘制完毕后,我将给定的位图发送到我的视图中,然后清除画布以便进行更多的绘制:

 private void sendImage2BackView()
 {
     //veeery extensive and boring code surpressed here

     //set the entire hocus-pocus' resulting bitmap as a resource for my view
     mView.setImageBitmap(tempBmp);
     mView.bringToFront();  


 }

我实现了一个扩展了 ScaleGestureDetector.SimpleOnScaleGestureListener 的 ScaleListener 类。

在 onScale 时刻,我会告诉我的画布我的缩放比例是多少:

@Override
public boolean onScale(ScaleGestureDetector detector) 
{   
    drawAction = ZOOM;      
    scaleFactor *= detector.getScaleFactor();
    scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));

    canvas.setScaleFactor(scaleFactor);
    return true;
}

然后,在我的视图(画布对象)中,我只需将比例设置为正在使用的视图:
    mView.setScaleX(factor);
    mView.setScaleY(factor);     

现在,最重要的部分来了,在 onScaleEnd 中,我调用一个方法,试图获取当前画布位图 AS IS,并将其发送到我的视图中,与其兄弟们和平共处,每个都有自己的大小和偏移量。
    public void setScaleEnd()
    {
         //Lots of more boring code surpressed here
         //....

         //I store the bitmap that was contained at the ImageView
         // IF anyone is present
         previousBmp = ((BitmapDrawable)mView.getDrawable()).getBitmap();

         //then, I create a brand new scaled bitmap,in order to 
         // acquire the same proportion of ZOOM that I've just applied
         tempBmp = Bitmap.createScaledBitmap(previousBmp,
            (int)(mView.getWidth()*scaleFactor),
            (int)(mView.getHeight()*scaleFactor), true);


         int height = (int)(mView.getHeight()*scaleFactor);
         int width = (int)(mView.getWidth()*scaleFactor);

         //set my matrix
         mMatrix = new Matrix();

         //give it the right proportion
         mMatrix.postScale(scaleFactor, scaleFactor);

         translationX = mView.getWidth() / 2 - width / 2;
         translationY = mView.getHeight() / 2 - height / 2;

         //give it some necessary translation amount
         mMatrix.postTranslate(translationX, translationY);

         //set the matrix to the view, and send the resized bitmap to my ImageView.
         mView.setImageMatrix(mMatrix);
         mView.setImageBitmap(tempBmp);
    }

现在,我已经尝试过将所有东西直接显示在画布上,并给它一个比例/平移量;也尝试着分别处理位图,然后将它们发送回新的干净画布。

但是,当应用一定的缩放量后,我仍然保持着笔画上的位移!!! 我只想画一些东西,进行缩放,继续画更多的东西,并使笔划停留在我正在绘制的位置!

这可能吗?

我刚刚在玩S Note应用程序,它完全符合我试图实现的目标。


1
不知道我能如何帮忙,但这是我在StackOverflow上看过的最详细的问题,恭喜! - Paladini
感谢@FernandoPaladini! - Former User of Mine
1
我已经走过这条路,建议您使用一个好的矢量渲染库。Android路径实现在渲染方面非常缓慢,并且在大尺寸(缩放)时曲线不平滑。寻找一个好的OpenVG实现。 - S.D.
@S.D. 这是我心中所想的事情,得在缩放时完善路径。谢谢! - Former User of Mine
1个回答

6

我希望向您提出一些解决方案,但我不确定它是否有效。

首先我需要澄清的是,您在这段代码中犯了一个很大的错误:

     tempBmp = Bitmap.createScaledBitmap(previousBmp,
        (int)(mView.getWidth()*scaleFactor),
        (int)(mView.getHeight()*scaleFactor), true);

假设您有一台分辨率为1280x800像素且比例因子为4x甚至10x的平板电脑。接下来,您将尝试相应地分配16MB40MB的位图!非常容易出现OutOfMemoryError错误,因此您需要采用另一种概念上的方法。
我建议您使用Picture类。
以下是具体步骤:
  1. 您需要确定向用户提供的原始图片的大小。
  2. 然后,您需要使用Picture.beginRecord(int width, int height)方法创建围绕您的图片的Canvas对象。
  3. 现在,您可以应用比例因子、平移画布并执行绘制操作。
  4. onDraw()方法中,您需要使用Picture.draw(Canvas canvas)方法,使用已应用于画布的相应设置(比例因子、平移)来绘制您的图片。
我没有尝试过这个解决方案,但是我希望Picture类能够帮助您。

2
嘿,@Olekssi Kropachov,非常感谢你的帮助。我会尝试一下,然后告诉你它是否有效。我之前不熟悉那个Picture类,看起来很不错! 还有感谢你关于图片调整大小的建议! - Former User of Mine
嘿,@Oleksii Kropachov,我尝试使用Picture对象,它看起来非常酷,应该可以很好地工作。但是,不幸的是,它根本没有起作用。除了完全没有硬件加速之外,我甚至无法让它绘制任何东西,更别说应用缩放和平移矩阵了。 - Former User of Mine
为了让您能够跟踪我的开发过程,我将代码直接放在了onDraw方法中: Picture picture = new Picture(); Canvas cnv = picture.beginRecording(_w, _h); cnv.drawColor(Color.CYAN); cnv.drawPath(mPath, mPaint); cnv.drawBitmap(mBitmap, 0, 0, mPaint); picture.draw(cnv); mCanvas.drawPicture(picture); picture.endRecording();但是它甚至没有在屏幕上显示我的笔画。 而如果我直接在画布上绘制,一切都很好 canvas.drawPath(mPath, mPaint); canvas.drawBitmap(mBitmap, 0, 0, mPaint); - Former User of Mine
你能以一种我们可以在设备上运行的方式上传代码吗?也许我要求太多了,但是尝试一下会很棒,谢谢... - agusgambina
1
@ClaudioFernandoMaciel 我遇到了类似的问题,你有两种状态,一种是用户绘制时,另一种是用户缩放时。在将视图带到前面并执行 drawView.translate(translationX, translationY) 之前,你需要检测用户何时要进行绘制。 - agusgambina
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接