前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手动测量 View 的宽高

手动测量 View 的宽高

作者头像
HelloVass
发布2018-09-12 10:29:36
1.3K0
发布2018-09-12 10:29:36
举报
文章被收录于专栏:Hellovass 的博客Hellovass 的博客

简单说明

手动调用 View 的 measure(int widthMeasureSpec,int heightMeasureSpec) 方法来得到 View 的宽高。

根据 View 的 LayoutParams 以下几种情况

具体数值(dp/px)

举个栗子,宽高都是 100 px,这时候,有我们来手动拼装合适的 MeasureSpec:

代码语言:javascript
复制
/**
   * 手动测量 View 的宽高,当 View 的宽高是精确值时
   *
   * @param target 需要测量的 View
   * @param widthSize 宽度
   * @param heightSize 高度
   */
  public void meaureManually(View target, int widthSize, int heightSize) {
    int widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
    int heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
    target.measure(widthMeasureSpec, heightMeasureSpec);
  }

wrap_content

代码语言:javascript
复制
/**
   * 手动测量 View 的宽高,当 View 的宽高是 wrap_content 时
   *
   * @param target 需要测量的View
   */
  public void measueManually(View target) {
    int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
    int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
    target.measure(widthMeasureSpec, heightMeasureSpec);
  }

这里有点儿小技巧,我将本来应该传入的 widthSizeheightSize 改为了 (1<<30)-1 ,看过 MeasureSpec 的源码就可以知道,这个特殊的 int 值就是 View 理论上能支持的最大值。

View 的尺寸使用 30 位二进制来表示,也就是说最大是 30 个 1(即 2^30 -1),也就是 (1<<30)-1。

match_parent

上一段 ViewGroup 的源码:

代码语言:javascript
复制
/**
     * Does the hard part of measureChildren: figuring out the MeasureSpec to
     * pass to a particular child. This method figures out the right MeasureSpec
     * for one dimension (height or width) of one child view.
     *
     * The goal is to combine information from our MeasureSpec with the
     * LayoutParams of the child to get the best possible results. For example,
     * if the this view knows its size (because its MeasureSpec has a mode of
     * EXACTLY), and the child has indicated in its LayoutParams that it wants
     * to be the same size as the parent, the parent should ask the child to
     * layout given an exact size.
     *
     * @param spec The requirements for this view
     * @param padding The padding of this view for the current dimension and
     *        margins, if applicable
     * @param childDimension How big the child wants to be in the current
     *        dimension
     * @return a MeasureSpec integer for the child
     */
    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                // 如果换我们来构造此时的 MeasureSpec,我们需要知道这个 size 的大小,然而并不能,所以放弃
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                // 如果换我们来构造此时的 MeasureSpec,我们需要知道这个 size 的大小,然而并不能,所以放弃
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        //noinspection ResourceType
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

发现如果要构造在 View 的宽高为 match_parent 时的 MeasureSpec,需要知道 parentSize,而此时因为无法知道 parentSize,所以直接放弃

NOTE

注意网上的一些奇怪代码,还是举两个常见的栗子:

栗子一

代码语言:javascript
复制
view.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);

栗子二

代码语言:javascript
复制
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(-1, MeasureSpec.UNSPECIFIED);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(-1, MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);

第二个栗子最搞,现在在 Android Studio 里这么写编译器会直接给出错误提示,但是我以前经常能看到这样的代码(不明白原理的时候,我以前也这么做2333

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简单说明
  • 根据 View 的 LayoutParams 以下几种情况
    • 具体数值(dp/px)
      • wrap_content
        • match_parent
        • NOTE
          • 栗子一
            • 栗子二
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档