PaintCode 绘图代码 android 使用像素而不是点/DP
Posted
技术标签:
【中文标题】PaintCode 绘图代码 android 使用像素而不是点/DP【英文标题】:PaintCode drawing code android is using pixels instead of points/DP 【发布时间】:2017-09-27 14:59:35 【问题描述】:注意:是的,我知道在 android 中还有其他实现按钮的方法,但这只是演示我的问题的一个示例(实际的按钮要复杂得多)。所以请不要回复为Android中的按钮提供其他解决方案,我正在寻找PaintCode的解决方案......
多年来,我一直在使用 PaintCode 在 ios 中绘制自定义按钮,它运行良好。我想对 android 做同样的事情并遇到以下问题:
-
在 PaintCode 中,我绘制了一个按钮,该按钮基本上是一个半径为 20 点的圆角矩形。
我在周围画了一个框架,然后使用弹簧设置正确的调整大小行为(见屏幕截图)。
结果是,无论按钮的大小(= 框架)如何,边角都将始终采用 20 点的圆角。基本上是一个可调整大小的按钮。
这在 iOS 上运行良好,但在 android 上,半径是 20 像素,而不是点,导致半径从远到小(现在使用高分辨率设备)。
或者一般来说,我在 PaintCode 中使用 PaintCode 生成的 draw 方法绘制的所有绘图都很小。
生成的绘图代码似乎没有考虑设备的比例(就像在 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 中的错误吗?
【问题讨论】:
【参考方案1】:我是开发者。对不起,答案很长。
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
【讨论】:
将层更改为软件起到了作用(连同我在原始问题中提出的已经实现的缩放)。非常感谢您的快速答复和大力支持! 你可以看看这个问题***.com/questions/52069634/…【参考方案2】:我记得有一个类似的问题,在与 PaintCode 支持人员交谈后,我们想出了一个将 DP 转换为 PX 的函数。因此,比如说,在 Android 中,这 20 个点将被转换为“任意”像素——考虑到不同的显示密度。
长话短说,这是 PaintCode 支持答案的摘要:
Android 不支持设备独立像素的事实 绘图 API 是 iOS 和 安卓。使用 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
设为 PaintCode 中的外部参数,让每个平台负责提供其值。喜欢:
// In Android, convert 20DP to 20PX based on the above function.
// In iOS, just pass 20.
StyleKitName.drawButton1(canvas, frame, radius)
我希望这会有所帮助。
【讨论】:
我在这里面临同样的问题是我如何使用这个函数 Bitmap b = WJArtKit.imageOfIconInterviewUnfixedEmployerRequest(convertDPtoPX(0.2f,0.2f)); .但是图像仍然不清晰,我该怎么办? 你能看看这个问题***.com/questions/52069634/…以上是关于PaintCode 绘图代码 android 使用像素而不是点/DP的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI - 使用自定义绘图包装 UIView 时出现 UIViewRepresentable 故障
Xamarin.Forms PCL/SAP 自定义渲染,支持paintcode 3
Paintcode 为自定义按钮生成 iOS 代码(不工作)
Objective C - 从这个 PaintCode 代码创建 UIImage