我目前正在测试我在博客文章中找到的“ScalingLinearLayout”。 http://www.quadra-tec.net/~floppie/blag/2013/01/scalinglinearlayout-auto-scaling-layouts-in-android/。
我的问题是图形布局编辑器的主预览窗口是黑色的,而其他窗口显示预览(见下图)。
我之前在自定义组件中看到过类似的行为,但根据我的经验,总是没有显示任何内容。
有没有人见过这种行为并知道是什么原因造成的?
另请参阅下面的相关代码
图像中的示例布局:
<com.nightfox.testapp.ScalingLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:gravity="center"
android:orientation="vertical"
tools:context=".FlowA1" >
<RelativeLayout
android:layout_width="640px"
android:layout_height="960px"
android:gravity="center|bottom" >
<Button
android:id="@+id/button1"
android:layout_width="400px"
android:layout_height="200px"
android:layout_alignParentTop="true"
android:text="@string/no_set_alarm" />
<Button
android:id="@+id/button1"
android:layout_width="400px"
android:layout_height="200px"
android:layout_alignParentBottom="true"
android:text="@string/no_set_alarm" />
</RelativeLayout>
自定义 ScalingLinearLayout 如下所示:
package com.nightfox.testapp;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;
public class ScalingLinearLayout extends LinearLayout {
int baseWidth;
int baseHeight;
boolean alreadyScaled;
float scale;
int expectedWidth;
int expectedHeight;
public ScalingLinearLayout(Context context) {
super(context);
Log.d("notcloud.view", "ScalingLinearLayout: width=" + this.getWidth() + ", height=" + this.getHeight());
this.alreadyScaled = false;
}
public ScalingLinearLayout(Context context, AttributeSet attributes) {
super(context, attributes);
Log.d("notcloud.view", "ScalingLinearLayout: width=" + this.getWidth() + ", height=" + this.getHeight());
this.alreadyScaled = false;
}
public void onFinishInflate() {
Log.d("notcloud.view", "ScalingLinearLayout::onFinishInflate: 1 width=" + this.getWidth() + ", height=" + this.getHeight());
// Do an initial measurement of this layout with no major restrictions on size.
// This will allow us to figure out what the original desired width and height are.
this.measure(1000, 1000); // Adjust this up if necessary.
this.baseWidth = this.getMeasuredWidth();
this.baseHeight = this.getMeasuredHeight();
Log.d("notcloud.view", "ScalingLinearLayout::onFinishInflate: 2 width=" + this.getWidth() + ", height=" + this.getHeight());
Log.d("notcloud.view", "ScalingLinearLayout::onFinishInflate: alreadyScaled=" + this.alreadyScaled);
Log.d("notcloud.view", "ScalingLinearLayout::onFinishInflate: scale=" + this.scale);
if(this.alreadyScaled) {
Scale.scaleViewAndChildren((LinearLayout)this, this.scale, 0);
}
}
public void draw(Canvas canvas) {
// Get the current width and height.
int width = this.getWidth();
int height = this.getHeight();
// Figure out if we need to scale the layout.
// We may need to scale if:
// 1. We haven't scaled it before.
// 2. The width has changed.
// 3. The height has changed.
if(!this.alreadyScaled || width != this.expectedWidth || height != this.expectedHeight) {
// Figure out the x-scaling.
float xScale = (float)width / this.baseWidth;
if(this.alreadyScaled && width != this.expectedWidth) {
xScale = (float)width / this.expectedWidth;
}
// Figure out the y-scaling.
float yScale = (float)height / this.baseHeight;
if(this.alreadyScaled && height != this.expectedHeight) {
yScale = (float)height / this.expectedHeight;
}
// Scale the layout.
this.scale = Math.min(xScale, yScale);
Log.d("notcloud.view", "ScalingLinearLayout::onLayout: Scaling!");
Scale.scaleViewAndChildren((LinearLayout)this, this.scale, 0);
// Mark that we've already scaled this layout, and what
// the width and height were when we did so.
this.alreadyScaled = true;
this.expectedWidth = width;
this.expectedHeight = height;
// Finally, return.
return;
}
super.draw(canvas);
}
}
和规模类:
package com.nightfox.testapp;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
public class Scale {
public static void scaleContents(View rootView, View container) {
Scale.scaleContents(rootView, container, rootView.getWidth(), rootView.getHeight());
}
// Scales the contents of the given view so that it completely fills the given
// container on one axis (that is, we're scaling isotropically).
public static void scaleContents(View rootView, View container, int width, int height) {
Log.d("notcloud.scale", "Scale::scaleContents: container: " + container.getWidth() + "x" + container.getHeight() + ".");
// Compute the scaling ratio
float xScale = (float)container.getWidth() / width;
float yScale = (float)container.getHeight() / height;
float scale = Math.min(xScale, yScale);
// Scale our contents
Log.d("notcloud.scale", "Scale::scaleContents: scale=" + scale + ", width=" + width + ", height=" + height + ".");
scaleViewAndChildren(rootView, scale, 0);
}
// Scale the given view, its contents, and all of its children by the given factor.
public static void scaleViewAndChildren(View root, float scale, int canary) {
// Retrieve the view's layout information
ViewGroup.LayoutParams layoutParams = root.getLayoutParams();
// Scale the View itself
if(layoutParams.width != ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.width != ViewGroup.LayoutParams.WRAP_CONTENT) {
layoutParams.width *= scale;
}
if(layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.height != ViewGroup.LayoutParams.WRAP_CONTENT) {
layoutParams.height *= scale;
}
// If the View has margins, scale those too
if(layoutParams instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams)layoutParams;
marginParams.leftMargin *= scale;
marginParams.topMargin *= scale;
marginParams.rightMargin *= scale;
marginParams.bottomMargin *= scale;
}
root.setLayoutParams(layoutParams);
// Same treatment for padding
root.setPadding(
(int)(root.getPaddingLeft() * scale),
(int)(root.getPaddingTop() * scale),
(int)(root.getPaddingRight() * scale),
(int)(root.getPaddingBottom() * scale)
);
// If it's a TextView, scale the font size
/*
if(root instanceof TextView) {
TextView tv = (TextView)root;
tv.setTextSize(tv.getTextSize() * scale); //< We do NOT want to do this.
}
*/
// If it's a ViewGroup, recurse!
if(root instanceof ViewGroup) {
ViewGroup vg = (ViewGroup)root;
for(int i = 0; i < vg.getChildCount(); i++) {
scaleViewAndChildren(vg.getChildAt(i), scale, canary + 1);
}
}
}
}