【问题标题】:Get root dimension on profound child measure event获取深度子测量事件的根维度
【发布时间】:2014-03-18 05:42:32
【问题描述】:

在视图层次结构中:

Window > ViewGroup (root) > ViewGroup[...] > View (child)

我需要知道深子onMeasure事件中的根维度。

示例:

@Override
protected void onMeasure(int wMS, int hMS) {
    int desiredW = Math.round(rootW * factorW);
    int desiredH = Math.round(rootH * factorH);
    /* ... compute final dimensions ... */
    setMeasuredDimension(finalW, finalH);
}

注意:此时,getRootViewgetWindow 维度等于 0,因为孩子必须在父母之前setMeasuredDimention

考虑到很多孩子需要这个维度,就去做吧:

  • 我创建了一个界面:

    public interface OnRootSizeChanged {
        public void onRootSizeChanged(int w, int h);
    }
    
  • 我实现了我的孩子,它现在实现了OnRootSizeChanged 接口:

    private int rootW;
    private int rootH;
    @Override
    public void onRootSizeChanged(int w, int h) {
        rootW = w;
        rootH = h;
    }
    
  • 我实现了根视图:

    @Override
    protected void onMeasure(int wMS, int hMS) {
        int w = MeasureSpec.getSize(wMS);
        int h = MeasureSpec.getSize(hMS);
        dispatchOnRootSizeChange(this, w, h);
        super.onMeasure(wMS, hMS);
    }
    private void dispatchOnRootSizeChange(ViewGroup v, int w, int h) {
        for (int i = 0, n = v.getChildCount(); i < n; i++) {
            View child = v.getChildAt(i);
            if (child instanceof OnRootSizeChanged)
                ((OnRootSizeChanged) child).onRootSizeChanged(w, h);
            if (child instanceof ViewGroup)
                dispatchOnRootSizeChange((ViewGroup) child, w, h);
        }
    }
    

我的问题是:

  • 我是否有更简单的方法来做到这一点而无需递归或更好的实践?

更新:对于 ViewGroup[...] breabcrumb 中的 ViewPager 元素,此方法无效。当ViewPager 实例化子页面时,他们还没有收到OnRootSizeChanged 事件所以:

  • 孩子要问根维度,没有根告诉孩子他的维度

于是我从一个深奥的孩子那里搜索了如何定位root来问他:

  • getRootView() 似乎不是针对setContentView() 附加的视图
  • getWindow().getDecorView() 要么

一种可能的方法是:

  • 在孩子身上:

    @Override
    protected void onMeasure(int wMS, int hMS) {
        ViewParent parent = getParent();
        while (parent instanceof RootViewClass == false)
            parent = parent.getParent();
        RootViewClass root = (RootViewClass) parent;
        int desiredW = Math.round(root.w * factorW);
        int desiredH = Math.round(root.h * factorH);
        /* ... compute final dimensions ... */
        setMeasuredDimension(finalW, finalH);
    }
    
  • RootViewClass的根实例上:

    public int w, h;
    @Override
    protected void onMeasure(int wMS, int hMS) {
        w = MeasureSpec.getSize(wMS);
        h = MeasureSpec.getSize(hMS);
        super.onMeasure(wMS, hMS);
    }
    

但是对于很多孩子,我认为这不是一个好习惯。如果我可以在不使用循环的情况下找到根视图。

【问题讨论】:

  • 为什么不能简单地使用循环?视图层次结构深度应该很小,并且您应该在其他地方一次获得对父级的引用,这样您就不会在每次调用 onMeasure() 时都进行循环。
  • 如果我找不到其他解决方案,我会这样做,但我觉得这不是一个好习惯。另外,也许我忽略了一个更简单,更相关的解决方案?这是我的问题的对象
  • 你试图从孩子身上看到父母有什么限制,这也不是一个好习惯。我没有看到任何其他方式,但是您不需要循环,您只需要在这些子视图中引用对根的引用(您将在活动级别获得一个,因此您只需查找一次), 根,它将存储每次最后一个约束以使它们可用于子级。
  • 为了让您更好地理解我的目标,我开发了一个可调整大小的应用程序,它必须适应窗口的大小。所有的 UI 必须始终对用户可见(作为多屏幕尺寸的 openGL 游戏),小窗口的可滚动视图对我不感兴趣,我需要缩放所有视图。所以我所有的元素都取决于我的根视图尺寸。在大多数情况下,我使用父维度来计算子维度,但在某些情况下,我需要恢复根维度原点。可能是我以错误的方式参与?如果您有一些提示,我会非常认可
  • 为什么不自定义根布局呢?如果所有 UI 控件都必须可见,则此根视图将根据当前尺寸对其子级施加固定尺寸(这将进一步传播给它们的子级)。

标签: android android-layout


【解决方案1】:

您可以通过在收到这些值时将这些值存储在onMeasure() 方法中转发父级的大小,然后让子级通过Context 引用访问其onMeasure() 方法中的值:

// simple interface
public interface ParentRef {
   void YourViewGroup getRoot();
}

// the Activity implements the interface above
public class YourActivity extends Activity implements ParentRef {

   private YourViewGroup mRoot;

   //in onCreate initialize the mRoot reference

   @Override
   public YourViewGroup getRoot() {
      return mRoot;
   }
   //... rest of the Activity
}

// the custom ViewGroup will store the dimensions:
//fields in the root view
private int mCurWidth;
private int mCurHeight;

@Override
protected void onMeasure(int wMS, int hMS) {
    int w = MeasureSpec.getSize(wMS);
    int h = MeasureSpec.getSize(hMS);
    mCurWidth = w;
    mCurHeight = h;
    // now as the children are measured they can see the values above
    super.onMeasure(wMS, hMS);
}

public int getStoredWidth() {
    return mCurWidth;
}

public int getStoredHeight() {
    return mCurHeight;
}


// in the children's onMeasure simply do:
@Override
protected void onMeasure(int wMS, int hMS) {
   final YourViewGroup root = ((ParentRef) getContext()).getRoot();
   //width root.getStoredWidth()
   // height root.getStoredHeight()
   /* ... compute final dimensions ... */
   setMeasuredDimension(finalW, finalH);
} 

【讨论】:

  • 我现在不接受你的回答,因为我想寻找一种更简单的方法,但我感谢你对我的问题和这种有趣的方式感兴趣
【解决方案2】:

您可以使用 ViewTreeObserver (http://developer.android.com/reference/android/view/ViewTreeObserver.html)

//...get your view, than attach a viewTreeObserver on it!
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
   @Override
   public void onGlobalLayout() {
       //misure the view here, like view.getHeight()
   }
});

【讨论】:

  • 感谢您的回复,但是有两个主要问题:我没有轻松定位根视图的方法(我的主要问题),我需要在 OnMeasure 事件中定义子度量,OnLayout 是在 OnMeasure 之后调用。
  • 知道了。这个技巧怎么样:孩子第一次执行循环(并找到rootView)时,它在直接父级(或通过所有路径到根的每个祖先)上附加一个标签(setTag)。这样,孩子第二次尝试获取根时,它首先检查标签,如果它是!= null,它有根而不循环。
猜你喜欢
  • 2012-01-29
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
  • 2015-08-13
  • 2018-03-18
相关资源
最近更新 更多