Android -LinearLayoutまたはRelativeLayoutでビューのTopmargin/Bottommargin/etcをアニメーション化します
-
19-09-2019 - |
質問
下からスライドするメニューを作成しようとしています。画面の下部にあるメニューのビューから始まり、クリックするとスライドします。使用してみました TranslateAnimation
, 、しかし、ピクセルは移動しますが、メニューのヒット領域は以前と同じ位置にあります。ですから、アニメーションが完了した後にメニューのマージンを調整できれば、これは私が望むものを達成すると思います。ただし、マージンを調整する方法はわかりません。
私はaを作成しようとしました LinearLayout.LayoutMargins
オブジェクトしてからマージンを設定して、メニューのビューに適用します(これは LinearLayout
)、しかしこれはうまくいきません。
何か案は?
解決 2
私の解決策は、2つのLinearLayoutを作成することでした。1つは上昇状態(なくなって設定されています)、もう1つはメニューのダウンステートにあります。次に、ユーザーがボタンをクリックしてメニューをスライドさせると、 TranslateAnimation
メニューがスライドすることを表示します。アニメーションにリスナーを配置し、UP状態を表示し、アニメーションが終了するとダウン状態がなくなります。 「クロージング」アクションのためにこれを逆転させました。
私が元々それをすることを想像していた方法ではありませんでしたが、それはうまくいきました。
他のヒント
以下は私のために働きました。最初に、メニューが上(完全に見える)または下(そのほとんどが隠されている)のための底部のマージン(ディップ)を決定します。
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);
}
出来上がり!
使用 ViewPropertyAnimator
:
if (view.getY() != margin) {
view.animate().y(margin).setDuration(150).start();
}
これはハックが少し少ないと思います。基本的に、それはあなた自身のアニメーターを作っています。以下では、変更のみにセットアップされます topMargin
で RelativeLayout
, 、しかし、それを一般化するのは難しくありません。
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;
}
}
}
}
この投稿は、アニメーションを機能させるのに役立ちました。私の場合、フル画面のWebViewがあります。一部のユーザーアクションでは、このWebViewは右にスライドし、約70%をスライドし、新しいWebViewが左から出現し、利用可能なスペースを取ります。最終結果、新しいWebViewは70%(X軸)と残りの古いWebViewをカバーしています。 Arneのソリューションは私を非常に助けてくれました。アニメーションが完了するとすぐに、古いビューのマージンを設定しました。擬似コード:
marginParams.leftMargin = 336; //(70% of 480px)
しかし、私は奇妙な振る舞いに直面しました、私の古いウェブビュー(現在は30%のスペースしか占有していません)は、その内容を再フォーマットしていたと思いますが、それは今、それがただ滑っているかのように振る舞うのではなく、より小さなスペースに絞り込まれていると考えているかもしれません。右。言い換えれば、このマージンを設定するとすぐに、WebViewのHTMLレイアウトが変更されました。繰り返しますが、私はその理由と私のことを知りませんでした 推測してみて 親のウィンドウサイズが変更されたと思っていますか?その仮定に基づいて、もう1つのコードを追加しました。
marginParams.rightMargin = -336; //(same amount, but negative margin!)
そして、それはTrickを行い、HTMLコンテンツの再フォーマットはなく、両方のWebViewと並行してやり取りすることができました。
私はこれをアイデアについてArneに感謝し、また私が見た行動とその前提のためのインプットを取得してくれたことに感謝しています。私は実際に最終解決策が好きで、論理的な意味がありますが、私は間違っているかもしれません。 。 。考えや入力は大歓迎です。どうもありがとうございました。