精华内容
下载资源
问答
  • 2018-07-20 13:37:50

    以一个小的案例打印记录下自定义View中的各个方法的执行顺序。

    public class ProcessLinearLayout extends LinearLayout {
        public ProcessLinearLayout(Context context) {
            this(context,null);
        }
    
        public ProcessLinearLayout(Context context, @Nullable AttributeSet attrs) {
            this(context,attrs,0);
        }
    
        public ProcessLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(attrs);
        }
    
        private void init(AttributeSet attrs) {
            Log.e("执行顺序","---- init() -----");
            Log.e("执行顺序","init() 子View = "+getChildAt(0));
        }
    
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            Log.e("执行顺序","---- onFinishInflate() -----");
            View view = getChildAt(0);
            Log.e("执行顺序","onFinishInflate() 子View = "+view+"   高度 = "+view.getHeight());
    
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            Log.e("执行顺序","---- onMeasure() -----");
            View view = getChildAt(0);
            Log.e("执行顺序","onMeasure() 子View = "+view+"   高度 = "+view.getHeight());
            Log.e("执行顺序","onMeasure() 布局高度 "+getHeight());
            post(new Runnable() {
                @Override
                public void run() {
                    View view2 = getChildAt(0);
                    Log.e("执行顺序","post() 子View = "+view2+"   高度 = "+view2.getHeight());
                    Log.e("执行顺序","post() 布局高度 "+getHeight());
                }
            });
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
            Log.e("执行顺序","---- onLayout() -----");
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            Log.e("执行顺序","---- onSizeChanged() -----");
        }
    
        @Override
        public void onWindowFocusChanged(boolean hasWindowFocus) {
            super.onWindowFocusChanged(hasWindowFocus);
            Log.e("执行顺序","---- onWindowFocusChanged -----");
        }
    }
    E/执行顺序: init() 子View = null
    E/执行顺序: ---- onFinishInflate() -----
    E/执行顺序: onFinishInflate() 子View = android.support.v7.widget.AppCompatTextView{29442fc V.ED..... ......ID 0,0-0,0}   高度 = 0
    E/执行顺序: ---- onMeasure() -----
    E/执行顺序: onMeasure() 子View = android.support.v7.widget.AppCompatTextView{29442fc V.ED..... ......ID 0,0-0,0}   高度 = 0
    E/执行顺序: onMeasure() 布局高度 0
    E/执行顺序: ---- onSizeChanged() -----
    E/执行顺序: ---- onLayout() -----
    E/执行顺序: post() 子View = android.support.v7.widget.AppCompatTextView{29442fc V.ED..... ........ 0,100-720,138}   高度 = 38
    E/执行顺序: post() 布局高度 238
    E/执行顺序: ---- onWindowFocusChanged -----
    E/执行顺序: ---- onMeasure() -----
    E/执行顺序: onMeasure() 子View = android.support.v7.widget.AppCompatTextView{29442fc V.ED..... ......I. 0,100-720,138}   高度 = 38
    E/执行顺序: onMeasure() 布局高度 238
    E/执行顺序: ---- onLayout() -----
    E/执行顺序: post() 子View = android.support.v7.widget.AppCompatTextView{29442fc V.ED..... ........ 0,100-720,138}   高度 = 38
    E/执行顺序: post() 布局高度 238

    总结:

    从执行顺序分析

    init->onFinishInflate->onMeasure..->onSizeChanged->onLayout->post()->onWindowFocusChanged->onMeasure->onLayout

    由上可知,onMeasure和onLayout会被多次调用.

    附录:

    有一点我需要提及的是,我们在java代码中对某某View设置属性时,该api是在init()与 onMeasure()之间进行调用的。

    对于路径亦或者是宽高是不能在设置属性时进行参与绘制的。

    更多相关内容
  • 今天我们来聊聊 View 绘制流程的一小细节,自定义绘制顺序View 的三大流程:测量、布局、绘制,我想大家应该都烂熟于心。而在绘制阶段,ViewGroup 不光要绘制自身,还需循环绘制其一众子 View,这绘制策略...

    ViewGroup 默认顺序绘制子 View,如何修改?什么场景需要修改绘制顺序?

    今天我们来聊聊 View 绘制流程的一个小细节,自定义绘制顺序。

    View 的三大流程:测量、布局、绘制,我想大家应该都烂熟于心。而在绘制阶段,ViewGroup 不光要绘制自身,还需循环绘制其一众子 View,这个绘制策略默认为顺序绘制,即 [0 ~ childCount)。

    这个默认的策略,有办法调整吗?例如修改成 (childCount ~ 0],或是修成某个 View 最后绘制。同时又有什么场景需要我们做这样的修改?

    需要注意的是,绘制顺序会影响覆盖顺序,同时也会影响 View 的事件分发,这些都是关联影响的,可谓是牵一发而动全身。

    今天就来聊聊这个问题。

    二、TV App 的 Item 处理

    修改 View 的绘制顺序,在日常开发中,基本用不到。众多手机端 App 的 UI 设计,大部分采用扁平化的设计思想,除非是一些很特别的自定义 View,多数情况下,我们无需考虑 View 的默认绘制顺序。

    这也很好理解,正常情况下,ViewGroup 中后添加的 View,视觉上就是应该覆盖在之前的 View 之上。

    但是有一个场景的设计,很特别,那就是 Android TV App。

    在 TV 的设计上,因为需要遥控器按键控制,为了更丰富的视觉体验,是需要额外处理 View 对焦点状态的变化的。

    例如:获取焦点的 ItemView 整个高亮,放大再加个阴影,都是很常见的设计。

    那么这就带来一个问题,正常我们使用 RecyclerView 实现的列表效果,当 Item 之间的间距过小时,单个 Item 被放大就会出现遮盖的效果。

    例如上图所示,一个很常见的焦点放大高亮的设计,但却被后面的 View 遮盖了。

    这样的情况,如何解决呢?

     

    拍脑袋想,既然是间距太小了,那我们就拉大间距就好了。修改一个属性解决一个需求,设计师哭晕在工位上。

    不过确实有一些设计效果,间距足够,也就不存在遮盖的现象,例如 Bilibili TV 端的部分页面。

    但是我们不能只靠改间距解决问题,多数情况下,设计师留给我们的间距并不多。大部分 TV App 是这样的。

    既然逃不掉,那就研究一下如何解决。

    三、修改绘制顺序原理

    修改绘制顺序,其实很简单,Android 已经为我们留出了扩展点。

    我们知道,ViewGroup 通过其成员 mChildren 数组,存储子 View。而在 ViewGroup 绘制子 View 的 dispatchDraw() 方法循环中,并不是直接利用索引从 mChildren 数组中取值的。

    @Override
    protected void dispatchDraw(Canvas canvas) {
      // ...
      final ArrayList<View> preorderedList = usingRenderNodeProperties
            ? null : buildOrderedChildList();
      final boolean customOrder = preorderedList == null
            && isChildrenDrawingOrderEnabled();
      for (int i = 0; i < childrenCount; i++) {
        // ...
        final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
        // 并非直接从 mChildren 中获取
        final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
        if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
            more |= drawChild(canvas, child, drawingTime);
        }
      }
      // ...
    }
    

    可以看到,child 并非是从 mChildren 中直取,而是通过 getAndVerifyPreorderedView() 获得,它的参数除了 children 外,还有一个 preorderedList 的 ArrayList,及子 View 的索引。

    private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList,
            View[] children,
            int childIndex) {
      final View child;
      if (preorderedList != null) {
        child = preorderedList.get(childIndex);
        if (child == null) {
            throw new RuntimeException("Invalid preorderedList contained null child at index "
                    + childIndex);
        }
      } else {
        child = children[childIndex];
      }
      return child;
    }
    

    在其中,若 preorderedList 不为空,则从其中获取子 View,反之则还是从 children 中获取。

    回到前面 dispatchDraw() 中,这里使用的 preorderedList  关键列表,来自 buildOrderedChildList(),在方法中通过 getAndVerifyPreorderedIndex() 获取对应子 View 的索引,此方法需要一个 Boolean 类型的 customOrder,即表示是否需要自定义顺序。

    ArrayList<View> buildOrderedChildList() {
      // ...
      final boolean customOrder = isChildrenDrawingOrderEnabled();
      for (int i = 0; i < childrenCount; i++) {
        // add next child (in child order) to end of list
        final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
        final View nextChild = mChildren[childIndex];
        final float currentZ = nextChild.getZ();
        // insert ahead of any Views with greater Z
        int insertIndex = i;
        while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
            insertIndex--;
        }
        mPreSortedChildren.add(insertIndex, nextChild);
      }
      return mPreSortedChildren;
    }
    

    buildOrderedChildList() 的逻辑就是按照 Z 轴调整 children 顺序,Z 轴值相同则参考 customOrder 的配置。

    通常 ViewGroup 中的子 View,Z 值一致,所以关键参数是 customOrder 开关。

    从代码上了解到 customOrder 是通过 isChildrenDrawingOrderEnabled() 方法获取,与之对应的是 setChildrenDrawingOrderEnabled() 可以设置 customOrder 的取值。

    也就是说,如果我们要调整顺序,只需 2 步调整:

    1. 调用 setChildrenDrawingOrderEnable(true) 开启自定义绘制顺序

    2. 重写 getChildDrawingOrder() 修改 View 的取值索引

    四、实例

    最后,我们写个 Demo,重写 RecycleView 的 getChildDrawingOrder() 方法,来实现获得焦点的 View 最后绘制。

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
      View view = getLayoutManager().getFocusedChild();
      if (null == view) {
        return super.getChildDrawingOrder(childCount, i);
      }
      int position = indexOfChild(view);
      if (position < 0) {
        return super.getChildDrawingOrder(childCount, i);
      }
      if (i == childCount - 1) {
        return position;
      }
      if (i == position) {
        return childCount - 1;
      }
      return super.getChildDrawingOrder(childCount, i);
    }
    

    别忘了还需要调用 setChildrenDrawingOrderEnabled(true) 开启自定义绘制顺序。

    此时,焦点放大时,就不会被其他 View 遮挡。

    转自:https://mp.weixin.qq.com/s/G3BKLbu1gjIIf8-qY6DFBg


    延伸:

    ViewGroup及其子类如果要想指定子View的绘制顺序只需两步:

    1. setChildrenDrawingOrderEnabled(true) 开启自定义子View的绘制顺序;

    2. 用setZ(float),自定义Z值,值越大越优先绘制;


    重写getChildDrawingOrder,让gridview倒序绘制item

    最近要实现一个效果,gridview每个item加上动画,发现每个item都会被后面的item挡住,重写viewgroup的这个方法可实现倒叙绘制item,让后面的item绘制在前面item的底部。

    public class MyGridView extends GridView {
    public MyGridView(Context context, AttributeSet attrs) {//构造函数
            super(context, attrs);
            setChildrenDrawingOrderEnabled(true);
        }
     
        @Override
        protected int getChildDrawingOrder(int childCount, int i) {
            return childCount - i - 1;//倒序
        }
    }
    
    

    GridView 在TV上解决item放大时候,被其他item遮挡,单纯使用bringToFront无法解决的问题

    做过TV上使用GridView,对item进行放大的时候,会被后面或者其他item遮挡的问题,那么这个问题一般怎么解决呢?

    其实当我们遇到这样子的情况,使用bringToFront是无法解决问题的。

    其实我们要做的就是,要改变GridView对子view的绘制顺序,要将选中的item项绘制显示在顶层,所以要改变GridView的子View绘制顺序;

    /**
     * 
     * @author zhanghuagang 2017.7.6
     *
     */
    public class CommonGridView extends GridView {
    	private View mLastView = null;
    	private int mSelectedPosition;
    	/**
    	 * 
    	 * @author zhanghuagang 2017.7.6
    	 *
    	 */
    	public CommonGridView(Context context) {
    		this(context, null);
    	}
     
    	public CommonGridView(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    		setChildrenDrawingOrderEnabled(true);
    		setSmoothScrollbarEnabled(true);
    	}
     
    	public CommonGridView(Context context, AttributeSet attrs) {
    		this(context, attrs, 0);
    	}
     
    	@Override
    	protected void setChildrenDrawingOrderEnabled(boolean enabled) {
    		super.setChildrenDrawingOrderEnabled(enabled);
    	}
     
    	public int getSelectedPosition() {
    		return mSelectedPosition;
    	}
     
    	public void setSelectedPosition(int mSelectedPosition) {
    		this.mSelectedPosition = mSelectedPosition;
    	}
    	
    	@Override
    	public void draw(Canvas canvas) {
    		super.draw(canvas);
    	}
     
    	private void zoomInView(View v){
    		AnimatorSet animSet = new AnimatorSet();
    		float[] values = new float[] { 1.0f  ,1.18f  };
    		animSet.playTogether(ObjectAnimator.ofFloat(v, "scaleX", values),
    				ObjectAnimator.ofFloat(v, "scaleY", values));
    		animSet.setDuration(100).start();
    	}
    	
    	private void zoomOutView(View v){
    		AnimatorSet animSet = new AnimatorSet();
    		float[] values = new float[] { 1.18f  ,1.0f  };
    		animSet.playTogether(ObjectAnimator.ofFloat(v, "scaleX", values),
    				ObjectAnimator.ofFloat(v, "scaleY", values));
    		animSet.setDuration(100).start();
    	}
    	
     
    	
    	public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    		if(view!=null)
    	    zoomInView(view);
    	    if (view != mLastView && mLastView!=null) {
    	        zoomOutView(mLastView);
    	    }
    	    mLastView=view;
    	}
    	
    	
     
    	
    	/**
    	 * 此方法用来完美觉得item放大 ,绘制顺序出现问题的
    	 */
    	@Override
    	protected int getChildDrawingOrder(int childCount, int i) {
    	    if (this.getSelectedItemPosition() != -1) {
    	        if (i + this.getFirstVisiblePosition() == this.getSelectedItemPosition()) {// 这是原本要在最后一个刷新的item
    	            return childCount - 1;
    	        }
    	        if (i == childCount - 1) {// 这是最后一个需要刷新的item
    	            return this.getSelectedItemPosition() - this.getFirstVisiblePosition();
    	        }
    	    }
    	    return i;
    	}
     
     
    }
    
    

    首先我们是自定义view,在构造方法中将是否可以改变绘制顺序设置为true,改为可以。
    setChildrenDrawingOrderEnabled(true);
    然后,覆盖一下关键方法。
    getChildDrawingOrder方法,在这个中实现改变绘制顺序的逻辑,那么我们既然要在放大的时候,不被其他item遮挡,那么就必须在他选中的时候,将他绘制顺序放在最后,大改这个方法的实现逻辑如下。

        /**
         * 此方法用来完美解决item放大 ,绘制顺序出现问题的
         */
        @Override
        protected int getChildDrawingOrder(int childCount, int i) {
            if (this.getSelectedItemPosition() != -1) {
                if (i + this.getFirstVisiblePosition() == this.getSelectedItemPosition()) {// 这是原本要在最后一个刷新的item
                    return childCount - 1;
                }
                if (i == childCount - 1) {// 这是最后一个需要刷新的item
                    return this.getSelectedItemPosition() - this.getFirstVisiblePosition();
                }
            }
            return i;
        }


    第一行代码是判断,当前选中的item的position是否有效。
    代码逻辑很好理解,如果当前选中的子view是可见的,那么就将其设置为最后一个子view,来绘制,如果选中的是最后一个view,就返回他的真是有效的position,这样即可。

    原文链接:https://blog.csdn.net/hua631150873/article/details/74989666

     

    展开全文
  • view的执行过程,各种方法的调用先后顺序 这里只是测试各个方法的执行流程,有些时候就是这些小基础是非常重要的,下了测试代码如下: package com.world.hello.viewpagerindictor.view; import android.content....

    view的执行过程,各种方法的调用先后顺序

    这里只是测试各个方法的执行流程,有些时候就是这些小基础是非常重要的,下了测试代码如下:

    package com.world.hello.viewpagerindictor.view;
    
    import android.content.Context;
    import android.content.res.Configuration;
    import android.graphics.Canvas;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    
    /**
     * 自定义View的常用方法的调用先后顺序
     * Created by chengguo on 2016/3/18.
     */
    public class CustomView extends View {
    
        /**
         * 用java代码创建CustomView时调用此构成方法
         *
         * @param context
         */
        public CustomView(Context context) {
            super(context);
            Log.i("tag", "----  public CoustomView(Context context) ----");
        }
    
        /**
         * 用布局文件xml创建CustomView时调用此构成方法
         *
         * @param context
         */
        public CustomView(Context context, AttributeSet attrs) {
            super(context, attrs);
            Log.i("tag", "----  public CoustomView(Context context, AttributeSet attrs) ----");
        }
    
        public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            Log.i("tag", "----  public CoustomView(Context context, AttributeSet attrs, int defStyleAttr) ----");
        }
    
    
        /**
         * 使用布局文件XML创建CustomView时,在xml文件加载完成后调用这个方法
         */
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            Log.i("tag", "----  onFinishInflate() ----");
        }
    
        /**
         * CustomView的大小发生改变时调用这个方法
         *
         * @param w
         * @param h
         * @param oldw
         * @param oldh
         */
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            Log.i("tag", "----  onSizeChanged = " + " w = " + w + "  h = " + h + "  oldW = " + oldw + "  oldH = " + oldw);
        }
    
        /**
         * 在画布上面绘制
         *
         * @param canvas
         */
        @Override
        protected void dispatchDraw(Canvas canvas) {
            super.dispatchDraw(canvas);
            Log.i("tag", "----  dispatchDraw = ");
        }
    
        /**
         * 绘制CustomView时调用
         *
         * @param canvas
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Log.i("tag", "----  onDraw ----");
        }
    
        /**
         * 测量CustomView的大小
         *
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            Log.i("tag", "----  onMeasure ----");
        }
    
        /**
         * 将CustomView放置到父容器中去
         *
         * @param changed
         * @param left
         * @param top
         * @param right
         * @param bottom
         */
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            Log.i("tag", "----  onLayout ----");
        }
    
    
        /**
         * 将CustomView依附到Window中
         */
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            Log.i("tag", "----  onAttachedToWindow ----");
        }
    
        /**
         * 当手机屏幕从横屏和竖屏 相互转化时调用
         *
         * @param newConfig
         */
        @Override
        protected void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            Log.i("tag", "----  onConfigurationChanged ----");
        }
    
    }
    

          下面是Log信息,如下

    03-18 11:32:30.198 14844-14844/? I/tag: ----  public CoustomView(Context context, AttributeSet attrs) ----
    03-18 11:32:30.198 14844-14844/? I/tag: ----  onFinishInflate() ----
    03-18 11:32:30.227 14844-14844/? I/tag: ----  onAttachedToWindow ----
    03-18 11:32:30.228 14844-14844/? I/tag: ----  onMeasure ----
    03-18 11:32:30.294 14844-14844/? I/tag: ----  onMeasure ----
    03-18 11:32:30.295 14844-14844/? I/tag: ----  onSizeChanged =  w = 1080  h = 135  oldW = 0  oldH = 0
    03-18 11:32:30.295 14844-14844/? I/tag: ----  onLayout ----
    03-18 11:32:30.310 14844-14844/? I/tag: ----  onMeasure ----
    03-18 11:32:30.310 14844-14844/? I/tag: ----  onLayout ----
    03-18 11:32:30.311 14844-14844/? I/tag: ----  onDraw ----
    03-18 11:32:30.311 14844-14844/? I/tag: ----  dispatchDraw = 
    


            经过log测试,就知道了,View的方法的执行过程,那么在自定义View的时候,就会在正确的方法中,进行操作。
            希望对大家有所帮助


    展开全文
  • Android之多个View同时动画

    万次阅读 2016-09-04 18:29:21
    本文主要是记录开发过程中遇到的坑 动画是为了提高交互性而在应用里增加的,单个动画的实现有好几种方式,比如 (View).animate().scaleY(0.5f)....要实现多个view 同时动画,也提供了方法 AnimatorSet,比如这样的效

    本文主要是记录开发过程中遇到的坑

    动画是为了提高交互性而在应用里增加的,单个动画的实现有好几种方式,比如

    (View).animate().scaleY(0.5f).alpha(0.5f).translationX(100f).setDuration(500).start();
    这是单个view属性动画的两种实现

    要实现多个view 同时动画,也提供了方法 AnimatorSet,比如这样的效果


    先说坑,两个view,上面一个叫top,上移,变小;下面一个叫bottom,只有上移

    首先,top 和 bottom 是两个单独的view,不能bottom里包含top,我一开始就是这么干的,结果无法实现同时动画。

    上面的view黑色部分,如果没有view(view没有初始化,没有显示出来)top 在移上去后会有一个闪动,给加个背景,不让其消失就好了

    android:background="@drawable/border_top"
    
    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item >
            <shape >
                <stroke android:width="1dp" android:color="#00000000"/>
            </shape>
        </item>
    
    </layer-list>
    
    <!--  http://www.thinksaas.cn/topics/0/213/213132.html -->

    布局文件(测试)

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout 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">
    
       
        <FrameLayout
            android:id="@+id/pic_take_pic_big_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:paddingBottom="@dimen/common_measure_6dp"
            >
    
            <ImageView
                android:id="@+id/pic_dynamic_lv3_item_like"
                android:layout_gravity="bottom"
                android:layout_width="@dimen/common_measure_40dp"
                android:layout_height="@dimen/common_measure_40dp"
                android:padding="@dimen/common_measure_10dp"
                android:src="@drawable/unlike"
                android:visibility="gone"
                />
    
           
    
        </FrameLayout>
    
        <!-- dynamic 把这个控件放到屏幕最底下 -->
    
        <LinearLayout
            android:id="@+id/pic_dynamic_recycle_view"
            android:layout_width="match_parent"
            android:layout_height="@dimen/common_measure_184dp"
            android:layout_alignParentBottom="true"
            android:background="@color/white"
            android:orientation="vertical"
            android:paddingBottom="@dimen/common_measure_3dp"
            android:visibility="gone"
            >
    
          
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:background="#e5e5e5" />
    
            
    
        </LinearLayout>
    
    
    </RelativeLayout>

    动画

    AnimatorSet animatorSet;
        int drawableId;
    
        // 两个动画同时 TODO
        protected void showDynamic(int id) {
    
            drawableId = id;
    
            animatorSet = new AnimatorSet();
    
            dynamicRecycleView.setVisibility(View.VISIBLE);
            dynamicRecycleView.post(new Runnable() {
                @Override
                public void run() {
                    int height = dynamicRecycleView.getMeasuredHeight();
                    // view 移动
                    ObjectAnimator animator = ObjectAnimator.ofFloat(dynamicRecycleView, "translationY", height, 0f);
                    // 移动 + 缩小
                    ObjectAnimator animator1 = ObjectAnimator.ofFloat(cameraView, "translationY", -(height - 10));
                    ObjectAnimator animator2 = ObjectAnimator.ofFloat(bigCameraView, "scaleX", 0.73f);
                    ObjectAnimator animator3 = ObjectAnimator.ofFloat(bigCameraView, "scaleY", 0.73f);
                    // 缩放中心
                    bigCameraView.setPivotX(bigCameraView.getMeasuredWidth() / 2);
                    bigCameraView.setPivotY(bigCameraView.getMeasuredHeight());
                    bigCameraView.invalidate();//显示的调用invalidate
    
                    animatorSet.play(animator1).with(animator2).with(animator3)// ;
                            .with(animator);
    
                    animatorSet.setDuration(600);
    //                animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
                    animatorSet.addListener(showListener);
                    animatorSet.start();
    
    
                }
            });
    
           
        }
    
        Animator.AnimatorListener showListener = new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
    
            }
    
            @Override
            public void onAnimationEnd(Animator animation) {
                if(drawableId != -1) {
                    bigCameraView.setImageResource(drawableId);
                }
            }
    
            @Override
            public void onAnimationCancel(Animator animation) {
    
            }
    
            @Override
            public void onAnimationRepeat(Animator animation) {
    
            }
        };
    
    
        protected void dismissDynamic(int id) {
            animatorSet = new AnimatorSet();
            int height = dynamicRecycleView.getMeasuredHeight();
            // 相对位置
            ObjectAnimator animator = ObjectAnimator.ofFloat(dynamicRecycleView, "translationY", 0f, height);
            ObjectAnimator animator1 = ObjectAnimator.ofFloat(cameraView, "translationY", -height, 0f);
            ObjectAnimator animator2 = ObjectAnimator.ofFloat(bigCameraView, "scaleX", 0.73f, 1f);
            ObjectAnimator animator3 = ObjectAnimator.ofFloat(bigCameraView, "scaleY", 0.73f, 1f);
    
    
            animatorSet.play(animator1).with(animator2).with(animator3).with(animator);
    
            animatorSet.setDuration(600);
            animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
            animatorSet.addListener(dismissListener);
            animatorSet.start();
            if (id != -1) {
                bigCameraView.setImageResource(id);
            }
    
    
        }
    
        Animator.AnimatorListener dismissListener = new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
    
            }
    
            @Override
            public void onAnimationEnd(Animator animation) {
                dynamicRecycleView.setVisibility(View.GONE);
            }
    
            @Override
            public void onAnimationCancel(Animator animation) {
    
            }
    
            @Override
            public void onAnimationRepeat(Animator animation) {
    
            }
        };
    




    展开全文
  • Android自定义view绘制顺序漫谈

    千次阅读 2018-04-28 12:02:11
      今天就跟大家说说自定义view里面的绘制顺序问题,因为有时候避免不了在同一地方绘制不同的view,那么就避免不了遮盖问题,这时候就就必须考虑绘制顺序的问题了。   说到绘制顺序就不得不提onDraw和...
  • 目录 前言: 1. 为什么项目Controller的接口方法...4. 拦截器处理顺序? 5. 理论知识 5.1 prehandle 5.2 拦截器的基本概念? 5.3 什么是servlet容器? 5.4 什么是过滤器? 5.4 拦截器与过滤器的区别 5.5 ...
  • 多个AsyncTask执行顺序:并行or串行

    千次阅读 2016-12-07 13:17:08
    AsyncTask作为一个优秀的封装,很多人都在用,可是我估计很多人并不清楚多个AsyncTask对象到底是串行执行的,还是并行执行的,如果是并行的,那么最多同时执行几个异步任务呢? 源码面前无秘密,我们看一下源代码就...
  • test2中多个子组件生命周期执行顺序是根据引入顺序执行的 test2跳转到test3生命周期调用顺序 test2-beforeRouteLeave -> test3-beforeRouteEnter -> test3-beforeCreate -> test3-created -> test3-...
  • [cpp] view plain copy print?#include&lt;stdio.h&gt;&nbsp;&nbsp;&nbsp;void&nbsp;main()&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
  • Laravel 多个中间件的执行顺序

    千次阅读 2018-07-09 14:09:15
    一个路由需要用到多个中间件,其中一个是 Laravel 自带的 auth 中间件。 发现这个中间件不管放在哪里,总是在自定义中间件之前执行。 如果业务需要自定义中间在 auth 之前执行,还是有办法的。 解决方案 观察...
  • 多个Filter 的执行顺序

    万次阅读 2014-04-25 13:10:02
    2)如果同为url-pattern或servlet-name,则会按照在web.xml中的声明顺序执行。 下面举例子: [html]   view plain copy < filter-mapping >   < filter-name...
  • iOS APP启动函数调用顺序~详解

    千次阅读 2017-06-30 00:43:54
    一、OC调用 C++ 会为静态创建的对象生成初始化器,与静态语言不同,OC基于Runtime机制可以用类的名字来实例化一类的对象。Runtime 维护了一张映射类名与类的全局表,当加载一 dylib 时,其定义的所有的类...
  • shell 执行顺序

    2021-05-16 08:18:22
    shell script 到今天,我还只能一顺序执行,尝试探索下其更加强大的功能。一主文件 main ,三个调用文件 shell1、shell2、shell3,调用文件差别仅仅在于显示内容不同。(main中不使用后台执行(&),那么显示...
  • UIViewController 中有很关于加载和卸载的方法,如:loadView, viewDidLoad, viewWillAppear, viewDidAppear, viewWillLayoutSubviews,viewDidLayoutSubviews,viewWillDisappear, viewDidDisappear.调试日志: ...
  • 在判断手势时需要精细的分清楚每个触摸事件以及每个View对事件的接收情况,在View,ViewGroup,Activity中都可以接收事件,在对事件进行处理时onInterceptTouchEvent、dispatchTouchEvent及onTouchEvent这三个函数的...
  • 1. vuex action调用另一action 2. action调用mutations 3. action调用外面的方法 主要用途: 在表单数据 增加,删除,保存,更新以后 重新刷新里面 例如上图,修改权限 和 删除完成以后需要重新更新列表里面的...
  • 类的构造函数调用顺序是什么?

    千次阅读 2010-11-22 09:36:00
    如果一个类有多个基类,基类的构造函数在继承类的构造函数之前被调用。基类的构造函数以被声明的顺序调用。下面是一个例子: class Y {...} class X : public Y {...} X one;  ...
  • onMeasure、onLayout、dispatchDraw调用顺序

    千次阅读 2016-10-13 10:15:31
    在Android中view如何完成绘制这过程介绍了很,但是很理论化的东西,最近重新整理一下,通俗的讲解一下。  View绘制过程就好比你向银行贷款,  在执行onMeasure的时候,好比银行告诉你大概贷款额度有多少?...
  • Android 屏幕(View)刷新机制(原理)

    千次阅读 多人点赞 2019-06-17 19:46:21
    前言:在平时开发项目的时候我们都知道生成一个view加入到window中,或者对显示的view调用其属性改变的方法亦或者启动在某个view上配置的动画就会让屏幕进行刷新达到自己想要的ui效果。但是咱们的代码是怎么触发屏幕...
  • 一个vue页面使用多个components

    万次阅读 2019-01-07 11:06:31
    第一步: 在compoents目录下创建多个组件;     第二步: 在App.vue中添加多个router-view标签,别忘了写name;       第三步:修改router目录下的index.js文件;  ...
  • [Hive]Lateral View使用指南

    万次阅读 多人点赞 2017-03-17 19:07:25
    1. 语法lateralView: LATERAL VIEW udtf(expression) tableAlias AS columnAlias (',' columnAlias)* fromClause: FROM baseTable (lateralView)*2. 描述Lateral View一般与用户自定义表生成函数(如explode())结合...
  • 自定义View注意的问题

    千次阅读 2022-01-13 14:40:43
    本文重点 关于自定义View的初始化方法 关于addSubview 关于frame与bounds ...通过验证说明:首先在CustomView的init方法中调用createUI方法。 - (instancetype)init { if (self = [super init]) {
  • Android View框架总结(二)View焦点

    万次阅读 2016-08-20 20:06:30
    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52263256前言:View框架写到第六篇,发现前面第...(PS:本篇文章中源码均是android 6.0,请知晓)本来之前说view下篇是写onMeasure
  • View的事件分发机制

    千次阅读 2022-02-27 01:15:18
    View的事件分发机制VIew的事件包括什么事件分发规则三事件分发方法传递规则功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一适合你的列表创建一...
  • Android中View的绘制流程

    千次阅读 2019-01-11 15:21:10
    介绍Android View的绘制流程,引出后续的异步消息、事件分发。 二、 ViewRootImpl 1. ViewRootImpl是什么 在API文档中如此描述ViewRootImpl: /** * The top of a view hierarchy, implementing the needed ...
  • Android6.0源码分析之View(一)

    万次阅读 2016-12-19 14:33:27
    目前对于view还处于学习阶段,本来打算学习结束之后再写一篇进行总结,但是发现自己自制力太差,学习效率太低,所以在此,边学边写博客,不仅督促自己完成对view的学习,而且还可以看看大家对于view有什么想知道的,...
  • android View类详解。

    千次阅读 2019-03-26 13:46:40
    个View在屏幕中占据一个矩形区域、并且负责绘制和事件处理。View是所有widgets的基础类,widgets是我们通常用于创建和用户交互的组件,比如按钮、文本输入框等等。子类ViewGroup是所有布局(layout)的基础类。...
  • 学习Android知识的时候突然想到一个问题,在这里使用了突然这个词,因为之前就已经了解过Android的生命周期,相信大家也都对其了如指掌,但在这里说的是多个Activity切换时的生命周期中的方法执行顺序。大家知道...
  • 序:最近在工作中使用到了各种自定义控件,也更深刻的理解了自定义控件的重要性,所以就建了一专栏来专门整理自定义控件的相关知识。我打算先从理论知识说起,然后再把项目中使用的自定义控件整理后写为博客发表...
  • Qt之QGraphicsView进阶篇

    万次阅读 多人点赞 2020-04-06 15:50:35
    作者:billy 版权声明:著作权归作者所有,商业转载请联系作者... 示例 拖拽和碰撞检测示例 github 源代码下载 网上的一3D模型示例 github 源代码下载 更请参考 Qt之QGraphicsView入门篇 Qt之QGraphicsView实战篇

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 202,721
精华内容 81,088
关键字:

多个view调用的顺序是