• invalidate和requestLayout


    Invalidate:
    To farce a view to draw,call invalidate().——摘自View类源码
    从上面这句话看出,invalidate方法会执行draw过程,重绘View树。
    当View的appearance发生改变,比如状态改变(enable,focus),背景改变,隐显改变等,这些都属于appearance范畴,都会引起invalidate操作。

    所以当我们改变了View的appearance,需要更新界面显示,就可以直接调用invalidate方法。

    View(非容器类)调用invalidate方法只会重绘自身,ViewGroup调用则会重绘整个View树。

    RequestLayout:
    To initiate a layout, call requestLayout(). This method is typically called by a view on itself when it believes that it can no longer fit within its current bounds.——摘自View源码

    从上面这句话看出,当View的边界,也可以理解为View的宽高,发生了变化,不再适合现在的区域,可以调用requestLayout方法重新对View布局。

    View执行requestLayout方法,会向上递归到顶级父View中,再执行这个顶级父View的requestLayout,所以其他View的onMeasure,onLayout也可能会被调用。

    总结:

    View绘制分三个步骤,顺序是:onMeasure,onLayout,onDraw。经代码亲测,log输出显示:调用invalidate方法只会执行onDraw方法;调用requestLayout方法只会执行onMeasure方法和onLayout方法,并不会执行onDraw方法。

    所以当我们进行View更新时,若仅View的显示内容发生改变且新显示内容不影响View的大小、位置,则只需调用invalidate方法;若View宽高、位置发生改变且显示内容不变,只需调用requestLayout方法;若两者均发生改变,则需调用两者,按照View的绘制流程,推荐先调用requestLayout方法再调用invalidate方法。

    requestLayout示例:实现可移动组件:https://blog.csdn.net/qq_39658819/article/details/78994308

    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.widget.FrameLayout;
     
    /**
     * 步骤一:自定义可移动组件
     * @author NewBies
     * @date 2017/12/26
     */
    public class VertexView extends android.support.v7.widget.AppCompatTextView{
     
        private int startX;
        private int startY;
        private int endX;
        private int endY;
        private FrameLayout.LayoutParams layoutParams;
     
        public VertexView(Context context) {
            super(context);
        }
     
        public VertexView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
     
        public VertexView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
     
     
        /**
         * 步骤二:重写onTouchEvent事件
         * @param event
         * @return
         */
        @Override
        public boolean onTouchEvent(MotionEvent event){
            //步骤三:获取手机触摸点的横坐标和纵坐标
            endX = (int)event.getX();
            endY = (int)event.getY();
     
            //步骤四:获取布局参数实例,注意:xx.LayoutParams这里的xx应该是该组件的父布局类型
            //注意:这句话必须在该组件已经添加到父布局中才会起作用,所以这句话我没有写在构造函数中,而是写在这里
            layoutParams = (FrameLayout.LayoutParams) this.getLayoutParams();
     
            switch (event.getAction()){
                //监听按下去的事件,这个事件在每次拖动时,必定会执行,也只执行一次
                case MotionEvent.ACTION_DOWN:
                    //将按下去的点记录为起始点
                    startX = endX;
                    startY = endY;
                    break;
                //步骤五:监听移动事件,该事件会在拖动时执行N次
                case MotionEvent.ACTION_MOVE:
                    //计算移动的距离
                    int offsetX = endX - startX;
                    int offsetY = endY - startY;
     
                    //调用layout方法来重新放置它的位置
                    layoutParams.setMargins(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
                    //刷新
                    requestLayout();
                    break;
                //监听抬起事件,该事件同按下去的时间一样,只执行一次
                case MotionEvent.ACTION_UP:
                    break;
                default:break;
            }
            //这里应该返回true,这里涉及到了android的事件拦截机制,大致意思是,我的事件是在哪里处理,就在那里的事件返回TRUE
            return  true;
        }
    }
  • 相关阅读:
    基于python实现二叉树的遍历 Marathon
    基于python实现链式队列代码 Marathon
    基于python常用排序与查找 Marathon
    elasticsearch要点及常用查询 Marathon
    elasticsearch练习 Marathon
    基于python实现单链表代码 Marathon
    gitlab 配置私人仓库 Marathon
    python虚拟环境的配置ubuntu 18.04 Marathon
    基于python实现顺序存储的队列代码 Marathon
    python实现elasticsearch操作CRUD API Marathon
  • 原文地址:https://www.cnblogs.com/genggeng/p/10014121.html
Copyright © 2020-2023  润新知