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

PaintCode drawing code android is using pixels instead of points/DP

注意:是的,我知道在 Android 中还有其他方法可以实现按钮,但这只是演示我的问题的示例(实际按钮要复杂得多)。所以请不要在 Android 中回复提供按钮的其他解决方案,我正在寻找 PaintCode 的解决方案...

我在 iOS 多年来一直使用 PaintCode 绘制自定义按钮,效果非常好。我想对 android 做同样的事情并遇到以下问题:

  1. 在 PaintCode 中我画了一个按钮,它基本上是一个半径为 20 点的圆角矩形。
  2. 我画了一个框架,然后使用弹簧设置正确的大小调整行为(见屏幕截图)。
  3. 结果是,无论按钮的大小(= 框架)是什么,角落总是会很好地圆润 20 点。基本上是一个很好调整大小的按钮。

这在 iOS 上效果很好,但在 android 上,半径是 20 像素 而不是点,导致半径很小(现在使用高分辨率设备)。

或者一般情况下,我在 PaintCode 中使用 PaintCode 生成的 draw 方法绘制的所有绘图都很小。

似乎生成的绘图代码没有考虑设备的比例(就像在 iOS 上那样)。

查看 https://www.paintcodeapp.com/documentation/android 部分 "scale" 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 中的错误吗?

我记得有过类似的问题,在与 PaintCode 支持人员交谈后,我们想出了一个将 DP 转换为 PX 的函数。因此,假设在 Android 中,这 20 个点将被转换为 "whatever" 像素——考虑到不同的显示密度。

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

The fact that Android doesn't support device independent pixels in its drawing API is the reason for the different behaviour of iOS and Android. When using UIKit, the coordinates entered are in Points, so it takes care of display density itself. When generating bitmap in Android the display density needs to be taken into account.

这是我创建的函数:

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));

当然,在这个例子中,由于项目的特殊性,我使用了 myButton (StyleKit.imageOfMyButton) 的位图。您需要调整示例以满足您的需要。

例如,您可以将 radius 作为 PaintCode 中的外部参数,让每个平台负责提供其值。喜欢:

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

希望对您有所帮助。

我是开发者。很抱歉回答太长。

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

首先,我完全理解其中的困惑,因为 iOS 它可以正常工作,而在 Android 中,您必须 fiddle 使用一些音阶。如果它能像我一样工作,它会更有意义,我会喜欢它,也会喜欢其他 PaintCode 用户。但这不是错误。问题是 UIKit 和 android.graphic.

之间的区别

在 UIKit 中,距离以点为单位进行测量。这意味着如果你画一个直径为 40 点的圆,它在各种 iOS 设备上应该大致相同。 PaintCode 采用了这一约定,您在 PaintCode 的用户界面中看到的所有数字,如形状的位置、笔划宽度或半径——一切都以点为单位。 PaintCode 生成的绘图代码不仅与分辨率无关(即你可以 resize/scale 它并保持清晰度),而且与显示密度无关(在视网膜显示器、常规显示器和视网膜高清显示器上呈现大致相同的尺寸).代码没有任何特别之处。它看起来像这样:

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