2

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

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

  1. 在 PaintCode 中,我绘制了一个按钮,该按钮基本上是一个半径为 20 点的圆角矩形。
  2. 我画了一个框架,然后使用弹簧设置正确的调整大小行为(见截图)。
  3. 结果是,无论按钮的大小(= 框架)如何,角落都将始终以 20 点圆润。基本上是一个可调整大小的按钮。

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

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

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

在此处输入图像描述

查看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 中的错误吗?

4

2 回答 2

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

于 2017-09-27T20:25:32.653 回答
3

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

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

Android 在其绘图 API 中不支持与设备无关的像素这一事实是 iOS 和 Android 行为不同的原因。使用 UIKit 时,输入的坐标是以点为单位的,因此它自己负责显示密度。在 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));

当然,在这个例子中,由于项目的具体情况,我使用了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)

我希望这有帮助。

于 2017-09-27T15:40:07.643 回答