Android 中长宽比不变的缩放布局
我想为我的应用程序创建一个 GUI,它本质上是一个背景图像,上面有一些控件。重要(且棘手)的部分是背景图像应保持其纵横比和比例(如果不完美则使用黑色边框),并且控件与背景图像的某些部分对齐。
我正在考虑通过继承 AbsoluteLayout (或我的它的副本,因为它已被弃用),正确缩放/定位它并让它绘制我的背景图像来解决这个问题。然后,我将使用缩放因子 [测量的布局大小] / [原始背景图像大小] 根据“缩放的绝对位置”放置其子项。
我的问题是,有更好的方法吗?这似乎是一种复杂的方式来做一些我认为相对常见的事情? (完美对齐背景图像像素上的按钮图像)。我感谢所有的指点和建议。
我最终使用了上述策略。为了完成,我做了以下事情:
我创建了一个 ScalingLayout 类,扩展 AbsoluteLayout,并添加了两个 xml 属性,这两个属性允许我为布局指定“虚拟尺寸”。这些是我放置视图的尺寸,布局确保在缩放整个布局时正确缩放这些相对位置。因此,在 xml 中,它看起来像:
<ScalingLayout
mynamespace:virtualWidth="100"
mynamespace:virtualHeight="100"
...
>
有关如何定义自定义 xml 属性并在类构造函数中获取这些值的信息,请查看以下问题:定义自定义属性
此外,我在 ScalingLayout 中重写了 onMeasure 和 onLayout。
// Overridden to retain aspect of this layout view
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
double aspect = getSize(widthMeasureSpec) / (double)getSize(heightMeasureSpec);
// Those are from XML layout
double virtualAspect = _virtualWidth / (double)_virtualHeight;
int width, height;
measureChildren(widthMeasureSpec, heightMeasureSpec);
if(aspect > virtualAspect) {
height = getSize(heightMeasureSpec);
width = height * virtualAspect;
} else {
width = getSize(widthMeasureSpec);
height = width / virtualAspect;
}
setMeasuredDimension(width, height);
}
...
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
double factor = (right - left) / (double)_virtualWidth;
nchildren = getChildCount();
for(int i = 0; i < nchildren; i++) {
View child = getChildAt(i);
LayoutParams lp = child.getLayoutParams();
// Scale child according to given space
child.layout(lp.x * factor,
lp.y * factor,
(lp.x + child.getMeasuredWidth()) * factor,
(lp.y + child.getMeasuredHeight()) * factor );
}
}
现在,只需在 XML 中添加视图并指定尺寸和位置,就像 AbsoluteLayout 一样,但要考虑虚拟尺寸。
I want to create a GUI for my app which is essentially a background image with some controls on top of it. The important (and tricky) part is that the background image should keep its aspect ratio and scale (with black borders if it's not a perfect fit), and that the controls are aligned with certain parts of the background image.
I was thinking of solving this by inheriting AbsoluteLayout (or my copy of it since it's deprecated), scaling/positioning it properly and have it draw my background image. Then, I would have it place its children according to "scaled absolute positions", using the scaling factor [Measured layout size] / [original background image size].
My question is, is there a better way to do this? It seems like a complicated way to do something I would believe is relatively common? (Aligning button images on a background image pixel perfectly). I'm thankful for all pointers and suggestions.
I ended up using the above strategy. For completion, here's what I did:
I created a class ScalingLayout, extending AbsoluteLayout, and added two xml attributes that allows me to specify "virtual dimensions" for the layout. Those are the dimensons I position my views along, and the layout makes sure those relative positions are scaled correctly when the whole layout is scaled. So in xml it looks like:
<ScalingLayout
mynamespace:virtualWidth="100"
mynamespace:virtualHeight="100"
...
>
For information on how to define custom xml attributes and getting those values in the class constructor, check out this question: Defining custom attrs
Furthermore, I overrided onMeasure and onLayout in my ScalingLayout.
// Overridden to retain aspect of this layout view
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
double aspect = getSize(widthMeasureSpec) / (double)getSize(heightMeasureSpec);
// Those are from XML layout
double virtualAspect = _virtualWidth / (double)_virtualHeight;
int width, height;
measureChildren(widthMeasureSpec, heightMeasureSpec);
if(aspect > virtualAspect) {
height = getSize(heightMeasureSpec);
width = height * virtualAspect;
} else {
width = getSize(widthMeasureSpec);
height = width / virtualAspect;
}
setMeasuredDimension(width, height);
}
...
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
double factor = (right - left) / (double)_virtualWidth;
nchildren = getChildCount();
for(int i = 0; i < nchildren; i++) {
View child = getChildAt(i);
LayoutParams lp = child.getLayoutParams();
// Scale child according to given space
child.layout(lp.x * factor,
lp.y * factor,
(lp.x + child.getMeasuredWidth()) * factor,
(lp.y + child.getMeasuredHeight()) * factor );
}
}
Now, just add views in XML and specify dimensions and positions just as for an AbsoluteLayout, but think in terms of the virtual dimensions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论