Android開発者サイトの次の例でFrameLayoutをズームしようとしています: http://developer.android.com/training/animation/zoom.html
私の具体的な問題は、アニメーションが最初に正しく、thumbView から展開され、2 回目にアニメーションが「どこか」(中央/上から中央) から来ることです。
私はほぼ同じですが、相違点は、ImageView の代わりに Framelayout があり、追加のメソッドでビューを最小化する関数を抽出することです。これは次のようになります。
private void zoomImageFromThumb(final View thumbView) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// here i building my custome layout
startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container)
.getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x + 15, -globalOffset.y + 60);
float startScale;
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
startScale = (float) startBounds.height() / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - startBounds.width()) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
} else {
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
}
thumbView.setAlpha(0f);
expandedImageView.setVisibility(View.VISIBLE);
expandedImageView.setPivotX(0f);
expandedImageView.setPivotY(0f);
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X,
startBounds.left, finalBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y,
startBounds.top, finalBounds.top))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X,
startScale, 1f)).with(ObjectAnimator.ofFloat(expandedImageView,
View.SCALE_Y, startScale, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
startBounds 変数はグローバルです。これは、最小化プロセスの位置を知るために必要なためです。ここで最小化メソッド:
private void minimizeViewFromThumb(final View thumbView) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator
.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.Y,startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView,
View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
このプロセス全体をデバッグすると、zoomViewFromThumb メソッドの getGlobalVisibleRect メソッドが別の値を与えることがわかります。
行をデバッグすると
finalBounds.offset(-globalOffset.x, -globalOffset.y);
最初の 2 つのパラメータは 0 と -60 で、2 回目 (最小化して再作成した後は 15 と 360 です。
なぜそれが起こるのか分かりません。
指定されたthumbViewからView.XおよびView.Yパラメーターの追加を設定しようとしました.ObjectAnimatorでView.X、View.Yパラメーターの定数値を操作しようとしましたが、問題を解決するものはありません。
今私を助けてください。
マヌに挨拶
1. 編集: Android バージョン 4.1.2 で失敗しました。Android 4.0 のエミュレーターでテストしたところ、正常に動作しました。
2. 編集: xml ファイルは次のとおりです。最初のファイルは、メインのアクティビティを表す xml ファイル (アニメーション付き) で、2 番目のファイルは、メインの xml の FrameLayout にプッシュする TableLayout を表します。(注意してください、現在私は仕事をしていて、元のファイルにアクセスできません。覚えている限り、これらの xml ファイルは正常です)
最初
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/relZoom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/frameZoomOne"
android:layout_width="160dp"
android:layout_height="215dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp" >
</FrameLayout>
<FrameLayout
android:id="@+id/frameZoomTwo"
android:layout_width="160dp"
android:layout_height="215dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp" >
</FrameLayout>
<FrameLayout
android:id="@+id/container"
android:layout_width="300dp"
android:layout_height="408dp"
android:visibility="invisible" >
</FrameLayout>
<FrameLayout
android:id="@+id/containerTwo"
android:layout_width="300dp"
android:layout_height="408dp"
android:visibility="invisible" >
</FrameLayout>
</RelativeLayout>
二番目
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tableLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TableRow
android:id="@+id/tableRow1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<TextView
android:id="@+id/textView1"
android:text="Column 1"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/textView2"
android:text="Column 2"
android:textAppearance="?android:attr/textAppearanceLarge" />
</TableRow>
<TableRow
android:id="@+id/tableRow2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<ImageView
android:id="@+id/imgView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/android" />
</TableRow>
<TableRow
android:id="@+id/tableRow3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dip" >
<TextView
android:id="@+id/textView3"
android:text="Column 3"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/textView4"
android:text="Column 4"
android:textAppearance="?android:attr/textAppearanceLarge" />
</TableRow>
</TableLayout>
3. 編集: xml ファイルを修正し、アクティビティを追加します。
public class SinglePlayerSp extends Activity implements OnClickListener
{
private final Context mContext = this;
private boolean mBackZoomOne = false;
private FrameLayout frameZoomOne;
private FrameLayout frameZoomTwo;
private static Animator mCurrentAnimatorOne;
private int mShortAnimationDuration;
private float startScaleOne;
private static Animator mCurrentAnimatorTwo;
private float startScaleTwo;
private Rect startBoundsOne;
private Rect startBoundsTwo;
private static View lastViewOne;
private static View lastViewTwo;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zoom);
frameZoomOne = (FrameLayout) findViewById(R.id.frameZoomOne);
frameZoomTwo = (FrameLayout) findViewById(R.id.frameZoomTwo);
frameZoomOne.setOnClickListener(this);
frameZoomTwo.setOnClickListener(this);
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
cardItems = getIntent().getParcelableArrayListExtra(CARD_ITEMS);
java.util.Collections.shuffle(cardItems);
}
private void flipCard(boolean playerOneDeck, final int selectionFromPlayer, final boolean result)
{
Card cardItemOne = null;
if (oneCards.get(0) != null)
{
cardItemOne = oneCards.get(0);
}
if (!mBackZoomOne)
{
getFragmentManager().beginTransaction().setCustomAnimations(R.animator.card_flip_right_in,
R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out).replace(
R.id.frameZoomOne, new CardBackFragment()).commit();
mBackZoomOne = true;
}
else
{
getFragmentManager().beginTransaction().setCustomAnimations(R.animator.card_flip_right_in,
R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out).replace(
R.id.frameZoomOne,
CardFrontFragment.newInstance(cardItemPlayerOne, selectionFromPlayer, playerOneDeck)).commit();
mBackZoomOne = false;
zoomViewOneFromThumb(frameZoomOne, cardItemOne);
}
}
private void zoomViewOneFromThumb(final View thumbView, final Card cardItem)
{
if (mCurrentAnimatorOne != null)
{
mCurrentAnimatorOne.cancel();
}
lastViewOne = thumbView;
View.getDefaultSize(0, 0);
final FrameLayout expandFrameLayout = (FrameLayout) findViewById(R.id.container);
LayoutInflater inflater =
(LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.fragment_card_front_clickable, null);
TableRow rowOne = (TableRow) layout.findViewById(R.id.tableRow1);
rowOne.setOnClickListener(this);
TextView cardone = (TextView) layout.findViewById(R.id.textView1);
TextView cardtwo = (TextView) layout.findViewById(R.id.textView2);
TextView cardthree = (TextView) layout.findViewById(R.id.textView3);
TextView cardfour = (TextView) layout.findViewById(R.id.textView4);
Locale locale = getApplicationContext().getResources().getConfiguration().locale;
cardone.setText(cardItem.TextOne());
cardtwo.setText(cardItem.getTextTwo());
cardthree.setText(cardItem.getTextThree());
cardfour.setText(cardItem.TextFour());
expandFrameLayout.addView(layout);
startBoundsOne = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
thumbView.getGlobalVisibleRect(startBoundsOne);
findViewById(R.id.containerSp).getGlobalVisibleRect(finalBounds, globalOffset);
startBoundsOne.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x + 15, -globalOffset.y + 50);
if ((float) finalBounds.width() / finalBounds.height() > (float) startBoundsOne.width()
/ startBoundsOne.height())
{
startScaleOne = (float) startBoundsOne.height() / finalBounds.height();
float startWidth = startScaleOne * finalBounds.width();
float deltaWidth = (startWidth - startBoundsOne.width()) / 2;
startBoundsOne.left -= deltaWidth;
startBoundsOne.right += deltaWidth;
}
else
{
startScaleOne = (float) startBoundsOne.width() / finalBounds.width();
float startHeight = startScaleOne * finalBounds.height();
float deltaHeight = (startHeight - startBoundsOne.height()) / 2;
startBoundsOne.top -= deltaHeight;
startBoundsOne.bottom += deltaHeight;
}
thumbView.setAlpha(0f);
expandFrameLayout.setVisibility(View.VISIBLE);
expandFrameLayout.setPivotX(0f);
expandFrameLayout.setPivotY(0f);
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator.ofFloat(expandFrameLayout, View.X, startBoundsOne.left, finalBounds.left)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.Y, startBoundsOne.top, finalBounds.top)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_X, startScaleOne, 1f)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_Y, startScaleOne, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter()
{
@Override
public void onAnimationEnd(Animator animation)
{
mCurrentAnimatorOne = null;
}
@Override
public void onAnimationCancel(Animator animation)
{
mCurrentAnimatorOne = null;
}
});
set.start();
mCurrentAnimatorOne = set;
startScaleFinal = startScaleOne; // with this or without this, i have the same problem
}
private void minimizeViewOne(final View expandFrameLayout)
{
AnimatorSet set = new AnimatorSet();
set.play(ObjectAnimator.ofFloat(expandFrameLayout, View.X, startBoundsOne.left)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.Y, startBoundsOne.top)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_X, startScaleFinal)).with(
ObjectAnimator.ofFloat(expandFrameLayout, View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter()
{
@Override
public void onAnimationEnd(Animator animation)
{
lastViewOne.setAlpha(1f);
expandFrameLayout.setVisibility(View.GONE);
mCurrentAnimatorOne = null;
}
@Override
public void onAnimationCancel(Animator animation)
{
lastViewOne.setAlpha(1f);
expandFrameLayout.setVisibility(View.GONE);
mCurrentAnimatorOne = null;
}
});
set.start();
mCurrentAnimatorOne = set;
}
}
これで完全なコードになりました。最後に onClick メソッドがあり、そこでユーザー アクションを受け取ります。そこから、minimizeView メソッドを呼び出し、いくつかのチェックを行った後、flipCard を呼び出します。それで全部です。