11

下から上にスライドするメニューを作成しようとしています。画面の下部に表示されているメニューのビューから始まり、クリックすると上にスライドします。を使ってみたのTranslateAnimationですが、ピクセルは動くものの、メニューのヒット領域は以前と同じ位置にあります。アニメーションが完成した後にメニューの余白を調整できれば、これで目的が達成できると思います。ただし、余白を調整する方法がわかりません。

LinearLayout.LayoutMarginsオブジェクトを作成し、その余白を設定してメニューのビュー ( ) に適用しようとしましたが、うまくいきLinearLayoutません。

何か案は?

4

5 に答える 5

21

以下は私のために働いた。最初に、メニューが上 (完全に表示されている) または下 (ほとんどが非表示) である下マージン (くぼみ) を決定します。

private static final int BOTTOM_MARGIN_UP = -50; // My menu view is a bit too tall.
private static final int BOTTOM_MARGIN_DOWN = -120;

次に、onCreate() で:

menuLinearLayout = (LinearLayout)findViewById(R.id.menuLinearLayout);
setBottomMargin(menuLinearLayout, BOTTOM_MARGIN_DOWN);

upAnimation = makeAnimation(BOTTOM_MARGIN_DOWN, BOTTOM_MARGIN_UP);
downAnimation = makeAnimation(BOTTOM_MARGIN_UP, BOTTOM_MARGIN_DOWN);

Button toggleMenuButton = (Button)findViewById(R.id.toggleMenuButton);
toggleMenuButton.setOnTouchListener(new View.OnTouchListener()
{
    public boolean onTouch(View view, MotionEvent motionEvent)
    {
        if (motionEvent.getAction() != MotionEvent.ACTION_DOWN) return false;
        ViewGroup.MarginLayoutParams layoutParams =
            (ViewGroup.MarginLayoutParams)menuLinearLayout.getLayoutParams();
        boolean isUp = layoutParams.bottomMargin == dipsToPixels(BOTTOM_MARGIN_UP);
        menuLinearLayout.startAnimation(isUp ? downAnimation : upAnimation);
        return true;
    }
});

そして、ここに秘密のソースが来ます;-)

private TranslateAnimation makeAnimation(final int fromMargin, final int toMargin)
{
    TranslateAnimation animation = 
        new TranslateAnimation(0, 0, 0, dipsToPixels(fromMargin - toMargin));
    animation.setDuration(250);
    animation.setAnimationListener(new Animation.AnimationListener()
    {
        public void onAnimationEnd(Animation animation)
        {
            // Cancel the animation to stop the menu from popping back.
            menuLinearLayout.clearAnimation();

            // Set the new bottom margin.
            setBottomMargin(menuLinearLayout, toMargin);
        }

        public void onAnimationStart(Animation animation) {}

        public void onAnimationRepeat(Animation animation) {}
    });
    return animation;
}

2 つのユーティリティ関数を使用します。

private void setBottomMargin(View view, int bottomMarginInDips)
{
    ViewGroup.MarginLayoutParams layoutParams =    
        (ViewGroup.MarginLayoutParams)view.getLayoutParams();
    layoutParams.bottomMargin = dipsToPixels(bottomMarginInDips);
    view.requestLayout();
}

private int dipsToPixels(int dips)
{
    final float scale = getResources().getDisplayMetrics().density;
    return (int)(dips * scale + 0.5f);
}

出来上がり!

于 2012-03-05T15:29:46.837 に答える
3

私の解決策は、2 つの LinearLayouts を作成することでした。1 つはアップ状態 (going に設定) で、もう 1 つはメニューのダウン状態です。次に、ユーザーがボタンをクリックしてメニューを上にスライドするとTranslateAnimation、メニューのスライドを表示する を呼び出します。アニメーションにリスナーを配置して、アニメーションが終了するとアップ状態が表示され、ダウン状態が消えるようにします。「閉じる」アクションではこれを逆にしました。

私が最初にそれを行うことを想像していた方法とはまったく異なりますが、うまくいきました.

于 2010-03-10T17:47:32.467 に答える
3

次を使用しViewPropertyAnimatorます。

if (view.getY() != margin) {
    view.animate().y(margin).setDuration(150).start();
}
于 2015-05-20T15:16:46.007 に答える
2

これはハックが少し少ないように感じます。基本的に、それはあなた自身のアニメーターを作ることです。以下では、 でのみ変更するように設定されてtopMarginRelativeLayoutますが、一般化するのは難しくありません。

import java.util.Calendar;

import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.RelativeLayout.LayoutParams;

public class MarginAnimation extends Thread {
    final String TAG = "MarginAnimation";
    long mStartTime;
    long mTotalTime;
    Interpolator mI;

    int mStartMargin;
    int mEndMargin;

    View mV;
    Activity mA;
    public MarginAnimation(Activity a, View v, 
            int startMargin, int endMargin, int totaltime,
            Interpolator i) {
        mV = v;
        mStartMargin = startMargin;
        mEndMargin = endMargin;
        mTotalTime = totaltime;
        mI = i;
        mA = a;
    }

    @Override
    public void run() {
        mStartTime = Calendar.getInstance().getTimeInMillis();
        while(!this.isInterrupted() && 
                Calendar.getInstance().getTimeInMillis() - mStartTime < mTotalTime) {

            mA.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(MarginAnimation.this.isInterrupted())
                        return;
                    long cur_time = Calendar.getInstance().getTimeInMillis();
                    float perc_done = 1.0f*(cur_time-mStartTime)/mTotalTime;

                    final int new_margin = (int)(1.0f*(mEndMargin-mStartMargin)*mI.getInterpolation(perc_done)) + mStartMargin;
                    LayoutParams p = (LayoutParams) mV.getLayoutParams();
                    Log.v(TAG, String.format("Setting Margin to %d", new_margin));
                    p.topMargin = new_margin;
                    mV.setLayoutParams(p);                  
                }
            });

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                return;
            }
        }
    }

}
于 2011-09-30T06:42:21.027 に答える
1

この投稿は、アニメーションを機能させるのに役立ちました。私の場合、全画面の Web ビューがあります。ユーザー アクションによっては、この Web ビューが約 70% 右にスライドし、新しい Web ビューが左から現れて、使用可能なスペースを占有します。最終的に、新しい WebView が 70% (x 軸) をカバーし、古い WebView が残りをカバーします。Arne のソリューションは、アニメーションが完了するとすぐに古いビューにマージンを設定するのに非常に役立ちました。擬似コード:

       marginParams.leftMargin = 336; //(70% of 480px)

しかし、私は奇妙な振る舞いに直面しました。私の古い Web ビュー (現在は 30% のスペースしか占めていません) がコンテンツを再フォーマットしていたと思います。右。つまり、このマージンを設定するとすぐに、webview の html レイアウトが変更されました。繰り返しますが、理由はわかりませんでしたが親ウィンドウのサイズが変更されたと思われます。その仮定に基づいて、コードをもう 1 行追加しました。

      marginParams.rightMargin = -336; //(same amount, but negative margin!)

そして、それはトリックであり、htmlコンテンツの再フォーマットはなく、両方のWebビューを並行して操作できます。

私はこれを投稿しています。アイデアを提供してくれたArneに感謝し、また、私が見た動作とそれに対する私の仮定についての入力を取得してくれたことに感謝します. 私は実際に最終的な解決策が好きで、論理的に理にかなっていますが、間違っているかもしれません. . . どんな考えや意見も大歓迎です。どうもありがとうございました。

于 2012-06-12T17:41:34.763 に答える