Android Custom FrameLayout和子测量

时间:2013-07-12 22:16:18

标签: android android-layout android-animation android-framelayout measurement

我需要您对我正在处理的自定义组件的建议。因此,很快,此组件的目的是调整自身大小并在需要时更改视图。所以现在我有一个组件工作:

public class SwitchBox extends FrameLayout {

    //Current view being displayed
    private View mCurrentView;
    //Tell if the custom is currently animating or not
    private boolean mAnimating = false;

    public SwitchBox(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //When all child are inflated, we set them all to alpha 0...
        for(int i = 0; i < getChildCount()-1; i ++) {
            getChildAt(i).setAlpha(0f);
            getChildAt(i).setVisibility(INVISIBLE);
            getChildAt(i).setClickable(false);
        }
        //Except for the displayed one which called mCurrentView
        mCurrentView = getChildAt(getChildCount()-1);
    }

    @Override
    public void bringChildToFront(View child) {

        mCurrentView.setClickable(false);
        //Animation set for the height and width animation
        AnimatorSet anim = new AnimatorSet();

        //Setting up width/height animation using nested classes WidthEvaluator and HeightEvaluator
        ValueAnimator scaleWidth = ValueAnimator.ofObject(new WidthEvaluator(this), getWidth(), child.getWidth());
        scaleWidth.setInterpolator(new AccelerateDecelerateInterpolator());
        scaleWidth.setDuration(600);
        ValueAnimator scaleHeight = ValueAnimator.ofObject(new HeightEvaluator(this), getHeight(), child.getHeight());
        scaleHeight.setInterpolator(new AccelerateDecelerateInterpolator());
        scaleHeight.setDuration(600);

        //Starting the alpha animation on the current view
        //and which end lanching the one on the "new" view
        final View view = child;
        final View current = mCurrentView;
        mCurrentView.animate().alpha(0f).setListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {}
            @Override
            public void onAnimationEnd(Animator animator) {
                view.setVisibility(VISIBLE);
                view.animate().alpha(1f).start();
                current.setVisibility(INVISIBLE);
                current.animate().setListener(null);
            }
            @Override
            public void onAnimationCancel(Animator animator) {}
            @Override
            public void onAnimationRepeat(Animator animator) {}
        }).start();

        //And then starting the width/height AnimatorSet
        anim.play(scaleWidth).with(scaleHeight);
        mAnimating = true;
        anim.start();

        anim.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {}
            @Override
            public void onAnimationEnd(Animator animator) {
                view.setClickable(true);
                mAnimating = false;
            }
            @Override
            public void onAnimationCancel(Animator animator) {}
            @Override
            public void onAnimationRepeat(Animator animator) {}
        });


        //Finally we change the current view for the new one and bring it to front
        mCurrentView = child;
        super.bringChildToFront(child);
    }

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

        //To avoid the childs' height and width changing permanently 
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY);
        measureChildren(widthMeasureSpec, heightMeasureSpec);

        //While animating we let android do its job
        if(!mAnimating) {
            //...then when is done we measure the view with the current displayed one
            //Mostly (entirely ?) for the initialisation of the component
            //but I coud not find another way to tell when all measurement was done  
            //Yet I tried onLayout/GlobalLayoutListener/... I think overriding onDraw was working well though 
            setMeasuredDimension(mCurrentView.getMeasuredWidth(), mCurrentView.getMeasuredHeight());
        }
    }

    //Class which allows width animation through ValueAnimator
    private class WidthEvaluator extends IntEvaluator {

        private View v;
        public WidthEvaluator(View v) {
            this.v = v;
        }

        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            Integer num = super.evaluate(fraction, startValue, endValue);
            ViewGroup.LayoutParams params = v.getLayoutParams();
            params.width = num;
            v.requestLayout();
            return num;
        }
    }
    //Class which allows height animation through ValueAnimator
    private class HeightEvaluator extends IntEvaluator {

        private View v;
        public HeightEvaluator(View v) {
            this.v = v;
        }

        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            Integer num = super.evaluate(fraction, startValue, endValue);
            ViewGroup.LayoutParams params = v.getLayoutParams();
            params.height = num;
            v.requestLayout();
            return num;
        }
    }
}

只要孩子们设置了特定的大小或WRAP_CONTENT,它就能正常工作。 现在,我想让一个FILL_PARENT的孩子减去一个保证金。我该怎么办? 我想也许想找到一种方法来知道孩子的测量值何时被设置为FILL_PARENT并给他MAX_WIDTH / MAX_HEIGHT维度,但看起来确实正确......

注1: 我可能已经找到了一种更简单的方法来制作动画:

...animate().scaleX(
     (float)nextView.getWidth()/(float)currentView.getWidth()
   ).scaleY(
     (float)nextView.getHeight()/(float)currentView.getHeight()
   );

但我不确定区别?我的测量问题怎么样,当我调整组件大小时,它会覆盖孩子们的宽度/高度?我做了一些测试,并没有覆盖我只用3个简单的视图作为孩子运行的测量

编辑:规模动画无法发挥作用显然它也会扩大所有孩子,傻我。

注2: 如果你想到任何其他方式来实现我的目标,或者你认为我没有朝着正确的方向前进,请不要犹豫,给我你的意见!

注3: 如果您想要/需要更多代码,我很乐意向您展示迄今为止所有代码。

0 个答案:

没有答案