欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android 百分比布局详解及实例代码

程序员文章站 2024-02-27 21:59:39
android 百分比布局 1.引入:compile 'com.android.support:percent:24.0.0' 2.点开源码可以看到,主要有两个布局类p...

android 百分比布局

1.引入:compile 'com.android.support:percent:24.0.0'

2.点开源码可以看到,主要有两个布局类percentframelayout和percentrelativelayout,一个工具类percentlayouthelper。
Android 百分比布局详解及实例代码

3.点开布局类比如percentrelativelayout的源码,可以看到实现的很简单。

public class percentrelativelayout extends relativelayout {
  private final percentlayouthelper mhelper = new percentlayouthelper(this);

  /**省略若干行构造方法之类的代码**/

  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {

    //重点在这

    mhelper.adjustchildren(widthmeasurespec, heightmeasurespec);
    super.onmeasure(widthmeasurespec, heightmeasurespec);
    if (mhelper.handlemeasuredstatetoosmall()) {
      super.onmeasure(widthmeasurespec, heightmeasurespec);
    }
  }

  @override
  protected void onlayout(boolean changed, int left, int top, int right, int bottom) {
    super.onlayout(changed, left, top, right, bottom);
    mhelper.restoreoriginalparams();
  }

  public static class layoutparams extends relativelayout.layoutparams
      implements percentlayouthelper.percentlayoutparams {
    private percentlayouthelper.percentlayoutinfo mpercentlayoutinfo;

    public layoutparams(context c, attributeset attrs) {
      super(c, attrs);
      mpercentlayoutinfo = percentlayouthelper.getpercentlayoutinfo(c, attrs);
    }

     /**省略若干行构造方法之类的代码**/

    @override
    public percentlayouthelper.percentlayoutinfo getpercentlayoutinfo() {
      if (mpercentlayoutinfo == null) {
        mpercentlayoutinfo = new percentlayouthelper.percentlayoutinfo();
      }

      return mpercentlayoutinfo;
    }

    @override
    protected void setbaseattributes(typedarray a, int widthattr, int heightattr) {
      percentlayouthelper.fetchwidthandheight(this, a, widthattr, heightattr);
    }
  }
}

就是在onmeasure和onlayout里面调用了percentlayouthelper 的一些方法,另外在里面定义了自己的layoutparams ,而这个layoutparams 也相当简单。

这里关键的一行代码是在onmeasure方法里面,mhelper.adjustchildren(widthmeasurespec, heightmeasurespec);通过percentlayouthelper 的adjustchildren 遍历子view来设置 子view的宽高,宽高在percentlayouthelper 的内部类percentlayoutinfo通过在布局文件中设置的值计算好了。

public void adjustchildren(int widthmeasurespec, int heightmeasurespec) {

    // calculate available space, accounting for host's paddings
    int widthhint = view.measurespec.getsize(widthmeasurespec) - mhost.getpaddingleft()
        - mhost.getpaddingright();
    int heighthint = view.measurespec.getsize(heightmeasurespec) - mhost.getpaddingtop()
        - mhost.getpaddingbottom();
    for (int i = 0, n = mhost.getchildcount(); i < n; i++) {

      //遍历子view来设置 子view的宽高

      view view = mhost.getchildat(i);
      viewgroup.layoutparams params = view.getlayoutparams();
      if (debug) {
        log.d(tag, "should adjust " + view + " " + params);
      }
      if (params instanceof percentlayoutparams) {
        percentlayoutinfo info =
            ((percentlayoutparams) params).getpercentlayoutinfo();

        if (info != null) {
          if (params instanceof viewgroup.marginlayoutparams) {
            info.fillmarginlayoutparams(view, (viewgroup.marginlayoutparams) params,
                widthhint, heighthint);
          } else {
            info.filllayoutparams(params, widthhint, heighthint);
          }
        }
      }
    }
  }

4.布局中的使用方法:以percentrelativelayout为例

<android.support.percent.percentrelativelayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@color/background_color"
  >

  <textview
    android:id="@+id/mian_tab_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:textcolor="@color/back_green"
    android:textsize="15sp"
    android:text="name"
    />

  <imageview
    app:layout_widthpercent="50%"
    app:layout_heightpercent="50%"
    android:src="@drawable/ic_launcher_icon"
    android:scaletype="fitxy"
    android:layout_below="@+id/mian_tab_name"
    android:background="@color/black"
    />

</android.support.percent.percentrelativelayout>

引入xmlns:app的命名空间,然后app:layout_widthpercent="50%"就可以设置宽高的百分比了。相当简单 。

5.不过在使用的过程中,可能会有一些其他的需求,比如app:layout_widthpercent="50%",app:layout_heightpercent="50%"都是相对于屏幕的宽高的,假如要显示一张正方形的图片,以宽的50%为准呢?这个时候就可以这样写了:

<imageview
    app:layout_widthpercent="50%"
    app:layout_aspectratio="100%"
    android:src="@drawable/ic_launcher_icon"
    android:scaletype="fitxy"
    android:layout_below="@+id/mian_tab_name"
    android:background="@color/cs_black"
    />

使用layout_aspectratio属性,设置app:layout_aspectratio="100%",layout_aspectratio就是宽高比。这个时候就不要设置app:layout_heightpercent属性了。在percentlayouthelper 里面, 源代码如下:

public void filllayoutparams(viewgroup.layoutparams params, int widthhint,
        int heighthint) {
      // preserve the original layout params, so we can restore them after the measure step.
      mpreservedparams.width = params.width;
      mpreservedparams.height = params.height;

      // we assume that width/height set to 0 means that value was unset. this might not
      // necessarily be true, as the user might explicitly set it to 0. however, we use this
      // information only for the aspect ratio. if the user set the aspect ratio attribute,
      // it means they accept or soon discover that it will be disregarded.
      final boolean widthnotset =
          (mpreservedparams.miswidthcomputedfromaspectratio
              || mpreservedparams.width == 0) && (widthpercent < 0);
      final boolean heightnotset =
          (mpreservedparams.misheightcomputedfromaspectratio
              || mpreservedparams.height == 0) && (heightpercent < 0);

      if (widthpercent >= 0) {
        params.width = (int) (widthhint * widthpercent);
      }

      if (heightpercent >= 0) {
        params.height = (int) (heighthint * heightpercent);
      }

      //这一段代码是关键,如果aspectratio >=0,aspectratio是宽高比

      if (aspectratio >= 0) {
        if (widthnotset) {

           //如果宽没有设置,就以高为准

          params.width = (int) (params.height * aspectratio);
          // keep track that we've filled the width based on the height and aspect ratio.
          mpreservedparams.miswidthcomputedfromaspectratio = true;
        }
        if (heightnotset) {

          //如果高没有设置,就以宽为准

          params.height = (int) (params.width / aspectratio);
          // keep track that we've filled the height based on the width and aspect ratio.
          mpreservedparams.misheightcomputedfromaspectratio = true;
        }
      }

      if (debug) {
        log.d(tag, "after filllayoutparams: (" + params.width + ", " + params.height + ")");
      }
    }

6.另外,假如我们要定义自己的percentlinearlayout,基本可以直接改一下名字,继承自linearlayout就好了:public class percentlinearlayout extends linearlayout ,在仿照percentrelativelayout里面的layoutparams定义一个自己的layoutparams就好了。

不过官方为什么没有直接提供一个percentlinearlayout 类,而只提供了两个percentframelayout和percentrelativelayout呢?或许是由于linearlayout 本身就有权重属性,自带百分比效果了。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!