Android onLayout()

Called from layout when this view should assign a size and position to each of its children

       onLayout()方法的注释就是安排自己的子View的位置,我们继承View的时候好像很少用到这个玩意。因为只是写一个控件根本不会存在子View的问题。
       接手别人的代码有个FlowLayout,搜索的时候出现历史记录的类似的View,但是换行的时候会出现问题。所以觉得可以自己搞个试试。
       首先要继承自ViewGroup这个类。直接重写方法,会发现一定要重写一个onLayout的方法。

public class FlowLayout extends ViewGroup {

public FlowLayout(Context context) {
    this(context,null);
}

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

public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

}
}

    之前的onMeasure()是对View的测量。这个onLayout()就是对View的位置进行摆放。写个简单的xml


Android onLayout()_第1张图片
xml布局.png

运行之后发现什么画面没有。这是当然的因为我们什么都没搞。那好现在开始填代码,我们在onLayout()方法中摆放控件。

    int count   = getChildCount() ;
    Log.e(TAG, "onLayout: "+count );
    for(int i =0 ;i

       这里是随便选的几个位置放一下,这里的layout四个参数分别是左上右下离父布局的距离。

Android onLayout()_第2张图片
初设layout.png

这样一看这个简单的代码能实现布局好像有点东西的。既然知道了onLayout()的功能了我们就直接一把梭吧, 思路:一个View 挨着一个View 当一行View多的放不下的时候自动换行。两个View之间来电间距。

    int count   = getChildCount() ;
    int indexX = 20;
    int indexY = 20;
    for(int i =0 ;i

       一把梭哈,先完成两个的View摆放,这个简单没什么问题。直接放第一个View 初始化一个开始位置(20,20)坐标点,然后开始向右边排。运行起来之后尴尬的事情发生了,UI上啥都没有。我们好像少了什么,一般都要先Measure的吧.ViewGroup中onMeasure主要是来调用measureChildren()方法。通过测量子View的大小然后在自己的View中设置宽高。加上方法,这里其实还有measureChildWithMargins(),这个可以获取到margins。先简单的设置一波。(这里其实要算子View的宽高的总和,再来设置FlowLayout的大小)

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

       实现效果如:

初见效果.png

       现在要设置两个View之间的间距,我们可以加一个属性来实现,现在改变一下代码,中间的间隔就出来了。
indexX=indexX+width+padding,下面得看一下换行的效果, 思路:当一行容不下要添加的View的时候我们要进行换行,即 A+B >ScreenWidth------->height+Y;还是直接走代码吧:

    int count   = getChildCount() ;
    int indexX = 20;
    int indexY = 20;
    for(int i =0 ;i getMeasuredWidth()){
           indexX = 20;
           indexY =indexY+ getChildAt(i-1).getMeasuredHeight()+padding;
        }
        child.layout(indexX,indexY,indexX+width,indexY+height);
        indexX=indexX+width+padding;
    }

       简单的代码就实现了,历史纪录的View,我们可以想想这里是通过xml中自己写的,那岂不是很傻,有时间写好像不如自己把东西画出来,当然当Item数量不固定的时候,好像也挺尴尬的。


Android onLayout()_第3张图片
再见效果图.png
  • 好吧我们进行第一次改良,需求设计成动态配置View的数量。

     public void addViewWithString(ArrayList list){
      this.removeAllViews();
      for(String string:list) {
          TextView textView = new TextView(mContext);
          textView.setText(string);
          this.addView(textView);
      }
     }
    

       首先移除之前的View,然后把TextView添加上去 ,实现效果


Android onLayout()_第4张图片
动态添加效果.png

这样看好丑,人家的TextView至少还有背景,这个动态添加的背景怎么搞,当然是在setTextView后面加上setBackground属性啦。当然最好是开一个属性在FlowLayout这个控件上面,让写布局的时候可以进行配置。
       但是问题来了,显示没毛病我要点击怎么办?设置一个点击事件吧,我们把方法改进一下直接上代码:

public void initDate(ArrayList list){
    this.removeAllViews();
    for(int i = 0;i

外部调用:

 FlowLayout flowLayout = findViewById(R.id.flowLayout);
     flowLayout.initDate(list);
    flowLayout.setiChildClickListener(new FlowLayout.IChildClickListener() {
        @Override
        public void childClickListener(String name, int position) {
            Toast.makeText(MainActivity.this,"第"+position+"个"+"--->"+name,Toast.LENGTH_LONG).show();
        }
    });

那么就可以实现点击事件以及效果了。好了,把代码整理一下加上背景。


Android onLayout()_第5张图片
加上点击效果.png

你可能感兴趣的:(Android onLayout())