PaintCode绘图代码android使用像素而不是点/ DP

时间:2017-09-27 14:59:36

标签: paint-code

注意:是的我知道在Android中有其他方法可以做按钮,但这只是一个展示我的问题的例子(执行按钮远比复杂得多)。所以请不要回复为Android中的按钮提供其他解决方案,我正在寻找使用PaintCode的解决方案......

我一直在使用PaintCode在iOS中绘制自定义按钮多年,它的工作非常出色。我想为Android做同样的事情,并有以下问题:

  1. 在PaintCode中,我绘制一个按钮,它基本上是一个半径为20磅的圆角矩形。
  2. 我画一个框架然后使用弹簧设置正确的调整大小行为(见截图)。
  3. 结果是,无论按钮的大小是多少(=框架),角落总是会有20个点的圆角。基本上是一个可调整大小的按钮。
  4. 这在iOS上运行得非常好,但在Android上,半径是20 像素而不是点,导致半径小到很小(现在使用高分辨率设备)。

    或者一般来说,当我使用PaintCode生成的draw方法绘制时,我在PaintCode中绘制的所有绘图都很小。

    它表示生成的绘图代码没有考虑设备的规模(就像在iOS上一样)。

    enter image description here

    查看https://www.paintcodeapp.com/documentation/android部分“比例”PaintCode建议在android中使用密度指标来执行缩放。 这确实有效,但是生成的图形模糊,我猜这是因为我们因缩放而绘制的分辨率较低。所以它不是一个可行的解决方案。

    class Button1 @JvmOverloads constructor(
            context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : Button(context, attrs, defStyleAttr) {
    
        var frame = RectF()
    
        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            val displayDensity = resources.displayMetrics.density
            canvas?.scale(displayDensity, displayDensity)
            frame.set(0f,0f,width.toFloat()/displayDensity,height.toFloat()/displayDensity)
            StyleKitName.drawButton1(canvas, frame)
        }
    }
    

    有什么建议可以解决这个问题吗?这是PaintCode中的错误吗?

2 个答案:

答案 0 :(得分:8)

我是开发人员。抱歉,答案很长。

TLDR:自己处理扩展,例如你的方式。将View的layerType切换为软件,以避免模糊的结果模糊。

首先,我完全理解这种困惑,对于iOS它只是起作用而在Android中你必须摆弄一些音阶。如果它只是我喜欢的那样,以及其他PaintCode用户也会更有意义。然而,这不是一个错误。问题是UIKit和android.graphic之间存在差异。

在UIKit中,距离以点数衡量。这意味着如果你绘制一个直径为40磅的圆圈,它在各种iOS设备上的尺寸应该更小。 PaintCode采用了这个约定,你在PaintCode的用户界面中看到的所有数字,如形状的位置,笔划宽度或半径 - 一切都在点。 PaintCode生成的绘图代码不仅与分辨率无关(即您可以调整大小/缩放它并保持清晰度),还可以独立显示密度(在视网膜显示器上显示相同的大小,常规显示和视网膜高清显示)。并且代码没有任何特殊之处。它看起来像这样:

NSBezierPath* rectanglePath = [NSBezierPath bezierPathWithRect: NSMakeRect(0, 0, 100, 50)];
[NSColor.grayColor setFill];
[rectanglePath fill];

因此显示缩放由UIKit处理。隐含的比例也取决于上下文。如果你在某个UIView子类的drawRect:中调用绘图代码,它会占用显示密度,但是如果你在自定义UIImage中绘图,它会获取该图像的密度。魔法。

然后我们添加了对Android的支持。 android.graphic中的所有度量都以像素表示。 Android没有做任何UIKit的“显示密度”魔术。另外,没有一种好方法可以找出绘图代码范围内的密度。您需要访问资源。所以我们可以将它作为参数添加到所有绘图方法中。但是,如果您不打算将图形发布到显示器但是您要创建图像(您要发送给您的朋友或其他什么),该怎么办?那么你不需要显示密度,而是图像密度。 好吧,如果添加一个参数,我们不应该添加资源,而是将密度本身作为浮点数并在每个绘图方法中生成缩放。现在如果你真的不关心密度怎么办?如果您关心的是您的绘图填充某个矩形并且可能具有最佳分辨率,该怎么办?实际上我认为通常就是这种情况。拥有如此多的不同显示分辨率和显示密度使得“一种物理尺寸的元素适合所有”的方法在我看来非常小。因此在大多数情况下,密度参数将是无关紧要的。我们决定留下如何处理用户规模的决定。

现在为缩放绘图的模糊。这是UIKit和android.graphics之间的另一个区别。所有开发人员都应该了解CoreGraphics在渲染具有多个对象的大型场景时速度不是很快。如果您正在编写性能敏感的应用程序,您应该考虑使用SpriteKit或Metal。这样做的好处是,您不必限制在CoreGraphics中可以执行的操作,并且您几乎总能获得非常准确的结果。缩放就是这样一个例子。你可以应用巨大的规模,结果仍然很清晰。如果您想要更多的硬件加速,请使用不同的API并自行处理限制(例如,您可以在GPU中放置大的纹理)。

Android走了其他路。他们的android.graphic api可以在两种模式下工作 - 没有硬件加速(他们称之为软件)或硬件加速(他们称之为硬件)。它仍然是相同的API,但其中一种硬件模式有一些重要的限制。这包括比例,模糊(因此阴影),一些混合模式等。 https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported

他们决定,如果目标API级别> = 14,默认情况下每个视图都将使用硬件模式。您当然可以将其关闭,并且神奇地缩放按钮将非常精彩。

我们在文档页面“层的类型”https://www.paintcodeapp.com/documentation/android部分提到您需要关闭硬件加速 它也在Android文档https://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling

答案 1 :(得分:3)

我记得有一个类似的问题,在与PaintCode支持人员交谈后,我们想出了一个将DP转换为PX的功能。因此,比如说,在Android中,这20个点将被转换为"无论如何"像素 - 考虑不同的显示密度。

长话短说,这是PaintCode支持答案的摘要:

  

Android并不支持设备无关的像素   绘图API是iOS和iOS行为不同的原因   Android系统。使用UIKit时,输入的坐标为Points,所以   它负责显示密度本身。在中生成位图时   Android需要考虑显示密度。

这是我创建的功能:

private static PointF convertDPtoPX(float widthDP, float heightDP) {
    Context context = getAppContext();
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    float widthPX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, widthDP, metrics);
    float heightPX = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightDP, metrics);

    return new PointF(widthPX, heightPX);
}

以下是如何调用它的示例:

Bitmap myButton = StyleKit.imageOfMyButton(convertDPtoPX(widthDP, heightDP));

当然,在此示例中,由于项目的具体情况,我使用了myButtonStyleKit.imageOfMyButton)的位图。您需要调整示例以满足您的需求。

例如,您可以在PaintCode中将radius作为外部参数,使每个平台都负责提供其值。像:

// In Android, convert 20DP to 20PX based on the above function.
// In iOS, just pass 20. 
StyleKitName.drawButton1(canvas, frame, radius)

我希望这会有所帮助。