Android Custom FrameLayout и дочернее измерение

Мне нужен ваш совет по пользовательскому компоненту, над которым я работаю. Таким образом, цель этого компонента - изменить его размер и изменить представление при необходимости. Так что сейчас у меня работает компонент:

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 ответов

Другие вопросы по тегам