2011-04-30 81 views
0

我正在创建自定义布局类,并且布局中的视图大小正确。 我遇到的问题是,如果我在其中包含另一个布局,所有嵌套视图的子级大小基本上都是全屏大小。自定义布局:嵌套视图的大小为全屏

XML布局代码 - FrameLayout内的内容尺寸不正确。

<CustomLayout> 
<ImageView android:layout_height="wrap_content" android:layout_width="wrap_content"/> 

<FrameLayout android:layout_height="wrap_content" android:layout_width="wrap_content"> 
    <!-- The views in here are sizing themselves as full screen. --> 
    <include layout="@layout/panel_emptypicture" android:id="@+id/EmptyPictureRelativeLayout" android:visibility="visible" /> 
</FrameLayout> 
<EditText android:layout_height="wrap_content" android:layout_width="wrap_content" /> 
<EditText android:layout_height="wrap_content" android:layout_width="wrap_content" /> 
</CustomLayout> 

自定义布局的Java代码。

@Override 
protected void onLayout(boolean changed, int l, int t, int r, int b) { 
    final int numChildren = getChildCount(); 

    Dimension d = new Dimension(0, 0, this.getWidth(), this.getHeight()); 
    final float scaleX = this.getWidth()/virtualWidth; 
    final float scaleY = this.getHeight()/virtualHeight; 

    for(int i = 0; i < numChildren; i++) { 
     final View child = getChildAt(i); 
     final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 
     final Dimension lpd = lp.getDimension(); 

     Dimension dest = lpd.scale(scaleX, scaleY, d); 
     child.layout(dest.x, dest.y, dest.width + dest.x, dest.height + dest.y); 
    } 
} 

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

    int width, height; 
    float maxWidth = MeasureSpec.getSize(widthMeasureSpec); 
    float maxHeight = MeasureSpec.getSize(heightMeasureSpec); 

    final float widthVirtualMultiplier = virtualWidth/virtualHeight; 
    final float heightVirtualMultiplier = virtualHeight/virtualWidth; 

     if(maxWidth * heightVirtualMultiplier < maxHeight) { 
      width = (int)maxWidth; 
      height = (int) (width * heightVirtualMultiplier); 
     } else { 
      height = (int)maxHeight; 
      width = (int)(height * widthVirtualMultiplier); 
     } 


    setMeasuredDimension(width, height); 

    // Tried adding this to see if it would do anything. Nope, no effect. 
    final int numChildren = getChildCount(); 
    for(int i = 0; i < numChildren; i++) { 
     final View child = getChildAt(i); 
     measureChild(child, widthMeasureSpec, heightMeasureSpec); 
    } 

} 
+0

你可以发布panel_emptypicture.xml吗?另外,CustomLayout还扩展了哪些类? – slund 2011-05-01 00:21:04

+0

panel_emptypicture.xml只是一个相对布局,每个角落都有一些按钮。 CustomLayout扩展了ViewGroup。它在FrameLayout之后建模,但具有完全不同的LayoutParams。 – 2011-05-01 04:00:05

回答

0

这最终是足够稳定的代码,以满足我的需求。它仍然有错误,但哦。

如果您需要其他引用的类,则整个项目位于此处。 http://code.google.com/p/motivatormaker-android/

package com.futonredemption.makemotivator.widget; 

import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.util.AttributeSet; 
import android.view.View; 
import android.view.ViewDebug; 
import android.view.ViewGroup; 

import com.futonredemption.makemotivator.util.RectUtils; 

public class ScaledCompositeLayout extends ViewGroup { 

    @ViewDebug.ExportedProperty(category = "virtual-measurement") 
    public float virtualHeight; 

    @ViewDebug.ExportedProperty(category = "virtual-measurement") 
    public float virtualWidth; 

    @ViewDebug.ExportedProperty(category = "clamp-width") 
    protected boolean clampOnWidth; 


    public ScaledCompositeLayout(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
    } 

    public ScaledCompositeLayout(Context context, AttributeSet attrs, 
      int defStyle) { 
     super(context, attrs, defStyle); 

     final TypedArray styleValues = context.obtainStyledAttributes(
         attrs, 
         com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout, 
         defStyle, 0); 

     virtualWidth = styleValues.getDimension(
         com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_VirtualWidth, 
         -1); 
     virtualHeight = styleValues.getDimension(
         com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_VirtualHeight, 
         -1); 
     clampOnWidth = styleValues.getBoolean(
       com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_ClampOnWidth, 
       false); 

     styleValues.recycle(); 

     if(virtualWidth == -1) { 
      throw new IllegalStateException("virtualWidth is required parameter."); 
     } 
     if(virtualHeight == -1) { 
      throw new IllegalStateException("virtualHeight is required parameter."); 
     } 
    } 

    @Override 
    protected void onLayout(boolean changed, int l, int t, int r, int b) { 
     final int numChildren = getChildCount(); 

     Rect parentRect = new Rect(0, 0, this.getWidth(), this.getHeight()); 
     final float scaleX = this.getWidth()/virtualWidth; 
     final float scaleY = this.getHeight()/virtualHeight; 

     for(int i = 0; i < numChildren; i++) { 
      final View child = getChildAt(i); 
      final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 
      final RectF lpr = lp.getRectF(); 

      Rect dest = RectUtils.scale(lpr, scaleX, scaleY, new RectF(parentRect)); 
      child.layout(dest.left, dest.top, dest.right, dest.bottom); 

      //Dimension out = dest; 
      //throw new IllegalStateException(String.format("Position: %d x %d -- Size: %d x %d", out.x, out.y, out.width, out.height)); 
     } 
    } 

    /** 
    * Uses the Virtual Width and Height to determine the ratio size of the actual layout. 
    * The layout_width and layout_height parameters are used to determine the maximum bounds. 
    */ 
    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 

     int width, height; 
     //int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
     //int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
     float maxWidth = MeasureSpec.getSize(widthMeasureSpec); 
     float maxHeight = MeasureSpec.getSize(heightMeasureSpec); 

     if (maxHeight == 0.0F) { 
      clampOnWidth = true; 
     } 

     final float widthVirtualMultiplier = virtualWidth/virtualHeight; 
     final float heightVirtualMultiplier = virtualHeight/virtualWidth; 

     //final float widthActualMultiplier = maxWidth/maxHeight; 
     //final float heightActualMultiplier = maxHeight/maxWidth; 
     /* 
     if(widthMode == MeasureSpec.EXACTLY) { 
      width = (int)maxWidth; 
      height = (int) (maxWidth * heightVirtualMultiplier); 
     } else if(heightMode == MeasureSpec.EXACTLY) { 
      width = (int)(maxHeight * widthVirtualMultiplier); 
      height = (int)maxHeight; 
     } else { // Use scaling */ 
      if(clampOnWidth || maxWidth * heightVirtualMultiplier < maxHeight) { 
       width = (int)maxWidth; 
       height = (int) (width * heightVirtualMultiplier); 
      } else { 
       height = (int)maxHeight; 
       width = (int)(height * widthVirtualMultiplier); 
      } 
     //} 

     setMeasuredDimension(width, height); 

     final int numChildren = getChildCount(); 
     final float scaleX = width/virtualWidth; 
     final float scaleY = height/virtualHeight; 
     final Rect parentRect = new Rect(0, 0, this.getWidth(), this.getHeight()); 

     for(int i = 0; i < numChildren; i++) { 
      final View child = getChildAt(i); 
      final LayoutParams lp = (LayoutParams) child.getLayoutParams(); 
      final RectF lpr = lp.getRectF(); 

      Rect dest = RectUtils.scale(lpr, scaleX, scaleY, new RectF(parentRect)); 

      this.measureChild(child, MeasureSpec.makeMeasureSpec(dest.width(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(dest.height(), MeasureSpec.EXACTLY)); 

      //Dimension out = dest; 
      //throw new IllegalStateException(String.format("Position: %d x %d -- Size: %d x %d", out.x, out.y, out.width, out.height)); 
     } 

     /* 
     for(int i = 0; i < numChildren; i++) { 
      final View child = getChildAt(i); 
      measureChild(child, widthMeasureSpec, heightMeasureSpec); 
     } 
     */ 

     //throw new IllegalStateException(String.format("%d x %d -- Physical: %.0f x %.0f -- Virtual: %.0f x %.0f", width, height, maxWidth, maxHeight, virtualWidth, virtualHeight)); 
    } 

    @Override 
    public LayoutParams generateLayoutParams(AttributeSet attrs) { 
     return new ScaledCompositeLayout.LayoutParams(getContext(), attrs); 
    } 

    @Override 
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 
     return p instanceof LayoutParams; 
    } 

    @Override 
    protected ViewGroup.LayoutParams generateLayoutParams(
      ViewGroup.LayoutParams p) { 
     return new LayoutParams(p); 
    } 

    public static class LayoutParams extends 
      android.view.ViewGroup.LayoutParams { 

     public RectF virtualRect = new RectF(); 

     public RectF getRectF() { 
      return virtualRect; 
     } 

     public LayoutParams(Context c, AttributeSet attrs) { 
      super(c, attrs); 
      float virtualWidth; 
      float virtualHeight; 

      TypedArray styleValues = c 
        .obtainStyledAttributes(
          attrs, 
          com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_Layout); 
      virtualRect.top = styleValues 
        .getDimension(
          com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_Layout_VirtualTop, 
          0); 
      virtualRect.left = styleValues 
        .getDimension(
          com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_Layout_VirtualLeft, 
          0); 
      virtualRect.right = styleValues 
        .getDimension(
          com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_Layout_VirtualRight, 
          0); 
      virtualRect.bottom = styleValues 
        .getDimension(
          com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_Layout_VirtualBottom, 
          0); 

      virtualWidth = styleValues 
        .getDimension(
          com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_Layout_VirtualWidth, 
          -1); 
      if (virtualWidth > 0) { 
       virtualRect.right = virtualRect.left + virtualWidth; 
      } 

      virtualHeight = styleValues 
        .getDimension(
          com.futonredemption.makemotivator.R.styleable.ScaledCompositeLayout_Layout_VirtualHeight, 
          -1); 
      if (virtualHeight > 0) { 
       virtualRect.bottom = virtualRect.top + virtualHeight; 
      } 

      styleValues.recycle(); 
     } 

     public LayoutParams(int width, int height) { 
      super(width, height); 
     } 

     public LayoutParams(ViewGroup.LayoutParams source) { 
      super(source); 
     } 
    } 
}