注意:是的我知道在Android中有其他方法可以做按钮,但这只是一个展示我的问题的例子(执行按钮远比复杂得多)。所以请不要回复为Android中的按钮提供其他解决方案,我正在寻找使用PaintCode的解决方案......
我一直在使用PaintCode在iOS中绘制自定义按钮多年,它的工作非常出色。我想为Android做同样的事情,并有以下问题:
这在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中的错误吗?
答案 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));
当然,在此示例中,由于项目的具体情况,我使用了myButton
(StyleKit.imageOfMyButton
)的位图。您需要调整示例以满足您的需求。
radius
作为外部参数,使每个平台都负责提供其值。像:
// In Android, convert 20DP to 20PX based on the above function.
// In iOS, just pass 20.
StyleKitName.drawButton1(canvas, frame, radius)
我希望这会有所帮助。