measure(0,0)方法的浅谈

本文介绍了一种自定义ListView的方法,包括如何通过监听视图树的全局布局事件来获取头部ImageView的尺寸,并实现平滑的动画效果。

1.此为activity中的代码

public class MainActivity extends Activity {

    private Mylistview lv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (Mylistview) findViewById(R.id.lv);
        View view = View.inflate(this, R.layout.header_view,null);
       final ImageView iv = (ImageView) view.findViewById(R.id.iv);
       lv.addHeaderView(view);
       为了能让自定义listview接收一个能够获取大小的view
       我们通过注册监听视图树的观察者在视图树的全局事件改变时得到通知
 lv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void onGlobalLayout() {
              lv.initHeader(iv);

                lv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });



        lv.setAdapter(new Myadapter());

    }
2.此处为自定义的listview
public class Mylistview extends ListView {
    private static final String TAG = "Mylistview";
    private int intrinsicHeight;
    private int measureHeight;
    private ImageView iv;
    private int showHeight;

    public Mylistview(Context context) {
        super(context);

    }
//MATCH_PARENT=-1 WRAP_CONTENT=-2
    public void initHeader(ImageView iv) {
        this.iv = iv;
//由于此iv是getviewtreeobserver方法穿过来的也就是说测量layout时已经测绘完成了穿过来的
        /**所以不用去进行下面的measure在去测量
         *
         */
//        final LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) iv.getLayoutParams();
//        int height = layoutParams.height;
//        int width = layoutParams.width;
//        int measureSpecWidth;
//        int measureSpecHeight;
//        if(height<0){
//            measureSpecHeight =  MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
//            Log.e(TAG, "height<0: "+measureSpecHeight );
//        }else{
//            measureSpecHeight = MeasureSpec.makeMeasureSpec(height,MeasureSpec.EXACTLY);
//            Log.e(TAG, "height>0: "+measureSpecHeight );
//        }
//        if(width<0){
//            measureSpecWidth = MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);
//            Log.e(TAG, "width<0: "+measureSpecWidth );
//
//        }else{
//            measureSpecWidth = MeasureSpec.makeMeasureSpec(width,MeasureSpec.EXACTLY);
//            Log.e(TAG, "width>0: "+measureSpecWidth );
//        }
//        iv.measure(measureSpecWidth,measureSpecHeight);


        showHeight = iv.getHeight();
        intrinsicHeight = iv.getDrawable().getIntrinsicHeight();
        measureHeight = iv.getMeasuredHeight();

        Log.e(TAG, "showHeight: "+ showHeight);
        Log.e(TAG, "measureHeight: "+ measureHeight);
        Log.e(TAG, "intrinsicHeight: "+ intrinsicHeight);
        /**通过测试可知measure(0,0)方法的用法
         * 我们首先找到此控件的layoutparams参数通过layoutparams.height和layouparams.width
         * 与0作比较来得到我们需要的widthMeasureSpec和heightMeasureSpec然后调用
         * measure(widthMeasureSpec,heightMeasureSpec)方法
         * 然后调用此控件的getMeasureHeight和getDrawable().getIntrinsicHeight()
         * 就可以得到此控件的赋值大小(我们赋予的)和原始高度(本来大小)
         *在开发中,可以通过getDrawable().getBounds().height()与getDrawable().getIntrinsicHeight()
         * 两种方法来获得图片资源的真实宽高
         * getHeight()为此控件在屏幕上显示的高度,与屏幕有关
         *
        *getMeasuredHeight()返回的是原始测量高度,与屏幕无关,
         * 因此可以知道getHeight()大小可以实时更新而getMeasureHeight不会改变当然图片真实宽高也不会改变
         * 实际上在当屏幕可以包裹内容的时候,他们的值是相等的,只有当view超出屏幕后,才能看出他们的区别。
         * 当超出屏幕后,getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的高度。
         例:
         <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="240dip"
         android:clipToPadding="false"
         android:scrollY="50dip" >
         </RelativeLayout>
        屏幕高度为190dip
         这里设置它的高度为240dip,超出屏幕50dip。
         getMeasuredHeight()获得的就是240dip的大小。(转换为像素值)
         getHeight()获得的是240dip - 50dip的大小。(转换为像素值)
         *
         *
         */


//        09-19 21:16:59.719 12219-12219/com.example.parallax E/Mylistview: height>0: 1073742224
//        09-19 21:16:59.719 12219-12219/com.example.parallax E/Mylistview: width<0: 0
//        09-19 21:16:59.719 12219-12219/com.example.parallax E/Mylistview: height1: 400
//        09-19 21:16:59.719 12219-12219/com.example.parallax E/Mylistview: measureHeight: 400
//        09-19 21:16:59.719 12219-12219/com.example.parallax E/Mylistview: intrinsicHeight: 976

//        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) iv.getLayoutParams();
//        layoutParams.height = 100;
//        iv.setLayoutParams(layoutParams);
//        iv.requestLayout();

    }

    public Mylistview(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

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


    @Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
 int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
        /**deltaY : 竖直方向的瞬时偏移量 / 变化量 dx   顶部到头下拉为-, 底部到头上拉为+
         scrollY : 竖直方向的偏移量 / 变化量
         scrollRangeY : 竖直方向滑动的范围
         maxOverScrollY : 竖直方向最大滑动范围
         isTouchEvent : 是否是手指触摸滑动, true为手指, false为惯性
         *
          */
        Log.e(TAG, "deltaY: " +deltaY + " scrollY: " + scrollY + " scrollRangeY: " + scrollRangeY
                + " maxOverScrollY: " + maxOverScrollY + " isTouchEvent: " + isTouchEvent);
        if(isTouchEvent&&deltaY<0){
               if(iv.getHeight()<intrinsicHeight){
           LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) iv.getLayoutParams();
                   layoutParams.height =  iv.getHeight()+Math.abs(deltaY/3);
                   iv.setLayoutParams(layoutParams);
//                   iv.getLayoutParams().height = iv.getHeight()+Math.abs(deltaY);
//                   iv.requestLayout();

               }

            }



  return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY,
maxOverScrollX, maxOverScrollY, isTouchEvent);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_UP:
                ResetAnimation reset = new ResetAnimation(iv.getHeight(),measureHeight,iv);
                startAnimation(reset);


//下面注释为值动画为我们的第二种方法上面为自定义动画
//                ValueAnimator obj =  ValueAnimator.ofInt(1);
//                obj.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//                    @Override
//                    public void onAnimationUpdate(ValueAnimator animation) {
//                        float fraction = animation.getAnimatedFraction();
////                        TypeEvaluator ctrl+h
//            Integer evaluate = evaluate(fraction, iv.getHeight(), measureHeight);
//     LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) iv.getLayoutParams();
//                  layoutParams.height = evaluate ;
//                        iv.setLayoutParams(layoutParams);
//
//                    }
//                });
////        Interpolator这个东西很难进行翻译,直译过来的话是补间器的意思,它的主要作用是可以控制
////          动画的变化速率,比如去实现一种非线性运动的动画效果。那么什么叫做非线性运动的
////          动画效果呢?就是说动画改变的速率不是一成不变的,像加速运动以及减速运动都属于非线性运动。
//                obj.setInterpolator(new OvershootInterpolator(5));
//                obj.setDuration(500);
//                obj.start();

            break;

        }

//此处要是返回true的话会消费掉此次touch事件导致onscrollby方法不能监听到~——~
        return super.onTouchEvent(ev);
    }
//    求值器
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}



3.此为resetAnimation的类自定义动画

public class ResetAnimation extends Animation{


    private  ImageView iv;
    private  int start;
    private  int end;

    public ResetAnimation(int start, int end, ImageView iv){
        this.start = start;
        this.end = end;
        this.iv = iv;
        setInterpolator(new OvershootInterpolator(5));
        setDuration(500);

    }
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
       iv.getLayoutParams().height = evaluate(interpolatedTime,start,end);
       iv.requestLayout();




        super.applyTransformation(interpolatedTime, t);
    }
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}




评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值