8

私は次のレイアウトを持っています:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_height="match_parent"
              android:layout_width="match_parent">

    <FrameLayout android:id="@+id/viewgroup_left"
                 android:layout_height="match_parent"
                 android:layout_weight="2"
                 android:layout_width="0dp">

        ... children ... 

    </FrameLayout>

    <LinearLayout android:id="@+id/viewgroup_right"
                  android:layout_height="match_parent"
                  android:layout_weight="1"
                  android:layout_width="0dp"
                  android:orientation="vertical">

        ... children ...

    </LinearLayout>

</LinearLayout>

私は次のようなものになります:

  +------------------------+------------+
  |                        |            |
  |                        |            |
  |         Left           |   Right    |
  |                        |            |
  |                        |            |
  +------------------------+------------+

特定のトグルが切り替えられたときに、左をアニメーション化して、その幅が画面全体に広がるようにします。同時に、Rightの幅をゼロに縮小するようにアニメートしたいと思います。後で、トグルが再び切り替えられたときに、上記の状態に戻す必要があります。

を呼び出す独自のアニメーションを作成しようとしましたView.getWidth()が、(設定によって)その値にアニメーション化するView.getLayoutParams().widthと、開始時よりも幅が広くなります。私はそれを間違っているだけだと思います。Honeycombアニメーションに関するすべてのドキュメントも読みましたが、変換したり拡大縮小したりしたくありません...レイアウト幅プロパティをアニメーション化したいと思います。この例は見つかりません。

これを行う正しい方法は何ですか?

4

3 に答える 3

12

まだ誰もあなたを助けておらず、私の最初の答えはとても混乱していたので、今回は正しい答えを出そうとします;-)

実際、私はこのアイデアが気に入っています。これは多くの人にとって役立つ素晴らしい視覚効果だと思います。右側のビューのオーバーフローを実装します (テキストが下部に拡大されているため、縮小が奇妙に見えると思います)。

とにかく、これは完全に正常に動作するコードです (アニメーション中にトグルすることもできます)。

簡単な説明:方向のブール値を使用して
呼び出すtoggleと、ハンドラー アニメーション呼び出しループが開始されます。これにより、方向と過去の時間に基づいて両方のビューの重みが増減します (計算とアニメーションをスムーズにするため)。アニメーション呼び出しループは、開始位置または終了位置に到達していない限り、それ自体を呼び出します。

レイアウト:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="10"
    android:id="@+id/slide_layout">
    <TextView
        android:layout_weight="7"
        android:padding="10dip"
        android:id="@+id/left"
        android:layout_width="0dip"
        android:layout_height="fill_parent"></TextView>
    <TextView
        android:layout_weight="3"
        android:padding="10dip"
        android:id="@+id/right"
        android:layout_width="0dip"
        android:layout_height="fill_parent"></TextView>
</LinearLayout>

アクティビティ:

public class TestActivity extends Activity {

    private static final int ANIMATION_DURATION = 1000;

    private View mSlidingLayout;
    private View mLeftView;
    private View mRightView;

    private boolean mAnimating = false;
    private boolean mLeftExpand = true;
    private float mLeftStartWeight;
    private float mLayoutWeightSum;
    private Handler mAnimationHandler = new Handler();
    private long mAnimationTime;

    private Runnable mAnimationStep = new Runnable() {
        @Override
        public void run() {
            long currentTime = System.currentTimeMillis();
            float animationStep = (currentTime - mAnimationTime) * 1f / ANIMATION_DURATION;
            float weightOffset = animationStep * (mLayoutWeightSum - mLeftStartWeight);

            LinearLayout.LayoutParams leftParams = (LinearLayout.LayoutParams)
                    mLeftView.getLayoutParams();
            LinearLayout.LayoutParams rightParams = (LinearLayout.LayoutParams)
                    mRightView.getLayoutParams();

            leftParams.weight += mLeftExpand ? weightOffset : -weightOffset;
            rightParams.weight += mLeftExpand ? -weightOffset : weightOffset;

            if (leftParams.weight >= mLayoutWeightSum) {
                mAnimating = false;
                leftParams.weight = mLayoutWeightSum;
                rightParams.weight = 0;
            } else if (leftParams.weight <= mLeftStartWeight) {
                mAnimating = false;
                leftParams.weight = mLeftStartWeight;
                rightParams.weight = mLayoutWeightSum - mLeftStartWeight;
            }

            mSlidingLayout.requestLayout();

            mAnimationTime = currentTime;

            if (mAnimating) {
                mAnimationHandler.postDelayed(mAnimationStep, 30);
            }
        }
    };

    private void toggleExpand(boolean expand) {
        mLeftExpand = expand;

        if (!mAnimating) {
            mAnimating = true;
            mAnimationTime = System.currentTimeMillis();
            mAnimationHandler.postDelayed(mAnimationStep, 30);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.slide_test);

        mLeftView = findViewById(R.id.left);
        mRightView = findViewById(R.id.right);
        mSlidingLayout = findViewById(R.id.slide_layout);

        mLeftStartWeight = ((LinearLayout.LayoutParams)
                mLeftView.getLayoutParams()).weight;
        mLayoutWeightSum = ((LinearLayout) mSlidingLayout).getWeightSum();
    }
}
于 2011-09-23T17:36:05.120 に答える
2

ここに私の2セントをKnickediの優れた回答に追加するだけです-誰かがそれを必要とする場合に備えて:

ウェイトを使用してアニメーション化すると、含まれているビューとビューグループでのクリッピング/非クリッピングの問題が発生します。これは特に、フラグメント コンテナとして重みのあるビューグループを使用する場合に当てはまります。それを克服するには、問題のある子ビューとビューグループ/フラグメント コンテナーのマージンをアニメーション化する必要があるかもしれません。

そして、これらすべてを一緒に行うには、ObjectAnimator と AnimatorSet (使用できる場合) と、MarginProxyなどのいくつかのユーティリティ クラスを使用することをお勧めします。

于 2014-06-02T11:20:01.737 に答える
1

@knickedi によって投稿されたソリューションの別の方法は、Runnable の代わりに ObjectAnimator を使用することです。アイデアは、ObjectAnimator を使用して左右両方のビューの重みを調整することです。ただし、ObjectAnimator がアニメートするプロパティとして重みを公開できるように、ビューをカスタマイズする必要があります。

まず、カスタマイズされたビューを定義します (例として LinearLayout を使用)。

public class CustomLinearLayout extends LinearLayout {
    public CustomLinearLayout(Context context) {
        super(context);
    }

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

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

    public void setMyWeight(float value) {
        LinearLayout.LayoutParams p = (LinearLayout.LayoutParams)getLayoutParams();
        p.weight = value;
        requestLayout();
    }
}

次に、レイアウト XML を更新して、このカスタム リニア レイアウトを使用します。

次に、アニメーションを切り替える必要がある場合は、ObjectAnimator を使用します。

ObjectAnimator rightView = ObjectAnimator.ofFloat(viewgroup_right, "MyWeight", 0.5f, 1.0f);
ObjectAnimator leftView = ObjectAnimator.ofFloat(viewgroup_left, "MyWeight", 0.5f, 0.0f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(1000); // 1 second of animation
animatorSet.playTogether(rightView, leftView);
animatorSet.start();

上記のコードは、両方のビューが線形レイアウトであり、最初は重量が半分であると想定しています。アニメーションは、右側のビューを最大重量まで拡大します (したがって、左側のビューは非表示になります)。ObjectAnimator は、カスタマイズされた線形レイアウトの「MyWeight」プロパティを使用してアニメーション化されることに注意してください。AnimatorSet を使用して左右の ObjectAnimator を結び付けているため、アニメーションがスムーズに見えます。

このアプローチにより、実行可能なコードとその内部の重み計算を記述する必要性が減りますが、カスタマイズされたクラスを定義する必要があります。

于 2015-11-23T08:25:06.580 に答える