新しいマテリアルデザインの仕様で説明されているように、「共有要素」を持つフラグメント間の遷移を実装しようとしています。私が見つけることができる唯一の方法は ActivityOptionsCompat.makeSceneTransitionAnimation で、これはActivityでのみ機能すると信じています。私はこれと同じ機能を探していますが、フラグメントを使用して/フラグメントを探しています。
私は同じ問題を抱えていましたが、別のフラグメントから新しいフラグメントを追加することで機能していました。次のリンクは、これを始めるのに非常に役立ちます。 https://developer.Android.com/training/material/animations.html#Transitions
動作するコードは次のとおりです。あるフラグメントから別のフラグメントにImageView
をアニメーション化しています。アニメーション化するView
が両方のフラグメントで同じAndroid:transitionName
を持っていることを確認してください。他のコンテンツは本当に重要ではありません。
テストとして、これを両方のレイアウトxmlファイルにコピーできます。画像が存在することを確認してください。
<ImageView
Android:transitionName="MyTransition"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:scaleType="centerCrop"
Android:src="@drawable/test_image" />
次に、res/transition
フォルダーにchange_image_transform.xmlという名前のファイルが1つあります。
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:Android="http://schemas.Android.com/apk/res/Android">
<changeImageTransform />
</transitionSet>
これで開始できます。画像を含むフラグメントAがあり、フラグメントBを追加するとします。
これをフラグメントAで実行します。
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.product_detail_image_click_area:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(Android.R.transition.explode));
// Create new fragment to add (Fragment B)
Fragment fragment = new ImageFragment();
fragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
fragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(Android.R.transition.explode));
// Our shared element (in Fragment A)
mProductImage = (ImageView) mLayout.findViewById(R.id.product_detail_image);
// Add Fragment B
FragmentTransaction ft = getFragmentManager().beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack("transaction")
.addSharedElement(mProductImage, "MyTransition");
ft.commit();
}
else {
// Code to run on older devices
}
break;
}
}
私はここに新しく、コメントすることができないので、これを回答として投稿しています。
共有要素フラグメントの遷移doは、ソースビューとターゲットビューに同じ(および一意の)transitionNameがある限り、ListViewで機能します。
リストビューアダプターを使用して、一意のtransitionNamesを必要なビューに設定する場合(たとえば、一定の+特定のアイテムID)および実行時に同じtransitionNamesをターゲットビューに設定するように詳細フラグメントを変更します( onCreateView)、トランジションは実際に動作します!
共有要素はフラグメントで機能しますが、留意すべき点がいくつかあります。
フラグメントのsharedElementsTransition
にonCreateView
を設定しようとしないでください。フラグメントのインスタンスを作成するとき、またはonCreate
でそれらを定義する必要があります。
Enter/exitトランジションとsharedElementTransitionの可能なアニメーションに関する公式ドキュメントに注意してください。それらは同じではありません。
試行錯誤 :)
私はそれについてコメントすることができないので、これは受け入れられた答えへのコメントでなければなりません。
受け入れられた答え(WindsurferOakおよびar34zによる)は機能しますが、backStackでナビゲートするときにnullポインター例外を引き起こす「マイナー」問題を除きます。元のフラグメントではなく、ターゲットフラグメントでsetSharedElementReturnTransition()
を呼び出す必要があるようです。
代わりに:
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
そのはず
fragment.setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
キーは、カスタムトランザクションを使用することです
_transaction.addSharedElement(sharedElement, "sharedImage");
_
2つのフラグメント間の共有要素遷移
この例では、2つの異なるImageViews
のいずれかをChooserFragment
からDetailFragment
に変換する必要があります。
ChooserFragment
レイアウトでは、一意のtransitionName
属性が必要です。
_<ImageView
Android:id="@+id/image_first"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:src="@drawable/ic_first"
Android:transitionName="fistImage" />
<ImageView
Android:id="@+id/image_second"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:src="@drawable/ic_second"
Android:transitionName="secondImage" />
_
ChooserFragments
クラスでは、クリックされたView
と、フラグメントの置換を処理している親Activity
にIDを渡す必要があります(IDが必要です) DetailFragment
)に表示する画像リソースを確認します。情報を親アクティビティに詳細に渡す方法は、別のドキュメントで確実に説明されています。
_view.findViewById(R.id.image_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 1);
}
}
});
view.findViewById(R.id.image_second).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 2);
}
}
});
_
DetailFragment
では、共有要素のImageView
にも一意のtransitionName
属性が必要です。
_<ImageView
Android:id="@+id/image_shared"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center"
Android:transitionName="sharedImage" />
_
DetailFragment
のonCreateView()
メソッドでは、どの画像リソースを表示するかを決定する必要があります(これを行わないと、共有要素は遷移後に消えます)。
_public static DetailFragment newInstance(Bundle args) {
DetailFragment fragment = new DetailFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_detail, container, false);
ImageView sharedImage = (ImageView) view.findViewById(R.id.image_shared);
// Check which resource should be shown.
int type = getArguments().getInt("type");
// Show image based on the type.
switch (type) {
case 1:
sharedImage.setBackgroundResource(R.drawable.ic_first);
break;
case 2:
sharedImage.setBackgroundResource(R.drawable.ic_second);
break;
}
return view;
}
_
親Activity
はコールバックを受け取り、フラグメントの置換を処理します。
_@Override
public void showDetailFragment(View sharedElement, int type) {
// Get the chooser fragment, which is shown in the moment.
Fragment chooserFragment = getFragmentManager().findFragmentById(R.id.fragment_container);
// Set up the DetailFragment and put the type as argument.
Bundle args = new Bundle();
args.putInt("type", type);
Fragment fragment = DetailFragment.newInstance(args);
// Set up the transaction.
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Define the shared element transition.
fragment.setSharedElementEnterTransition(new DetailsTransition());
fragment.setSharedElementReturnTransition(new DetailsTransition());
// The rest of the views are just fading in/out.
fragment.setEnterTransition(new Fade());
chooserFragment.setExitTransition(new Fade());
// Now use the image's view and the target transitionName to define the shared element.
transaction.addSharedElement(sharedElement, "sharedImage");
// Replace the fragment.
transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName());
// Enable back navigation with shared element transitions.
transaction.addToBackStack(fragment.getClass().getSimpleName());
// Finally press play.
transaction.commit();
}
_
忘れないでください-Transition
自体。この例では、共有要素を移動および拡大縮小します。
_@TargetApi(Build.VERSION_CODES.Lollipop)
public class DetailsTransition extends TransitionSet {
public DetailsTransition() {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform());
}
}
_
SharedElementをフラグメントで検索し、GitHubで非常に便利なソースコードを見つけました。
1.まず、両方のフラグメントレイアウトのオブジェクト(ImageViewのような)にtransitionNameを定義する必要があります(クリックイベントを処理するためにフラグメントAにボタンを追加します):
フラグメントA:
<ImageView
Android:id="@+id/fragment_a_imageView"
Android:layout_width="128dp"
Android:layout_height="96dp"
Android:layout_alignParentBottom="true"
Android:layout_centerHorizontal="true"
Android:layout_marginBottom="80dp"
Android:scaleType="centerCrop"
Android:src="@drawable/gorilla"
Android:transitionName="@string/simple_fragment_transition />
<Button
Android:id="@+id/fragment_a_btn"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentBottom="true"
Android:layout_centerHorizontal="true"
Android:layout_marginBottom="24dp"
Android:text="@string/gorilla" />
フラグメントB:
<ImageView
Android:id="@+id/fragment_b_image"
Android:layout_width="match_parent"
Android:layout_height="250dp"
Android:scaleType="centerCrop"
Android:src="@drawable/gorilla"
Android:transitionName="@string/simple_fragment_transition" />
change_image_transform.xml:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:Android="http://schemas.Android.com/apk/res/Android">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
</transitionSet>
フラグメントA:
public class FragmentA extends Fragment {
public static final String TAG = FragmentA.class.getSimpleName();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final ImageView imageView = (ImageView) view.findViewById(R.id.fragment_a_imageView);
Button button = (Button) view.findViewById(R.id.fragment_a_btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getFragmentManager()
.beginTransaction()
.addSharedElement(imageView, ViewCompat.getTransitionName(imageView))
.addToBackStack(TAG)
.replace(R.id.content, new FragmentB())
.commit();
}
});
}
}
フラグメントB:
public class FragmentB extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(Android.R.transition.move));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_b, container, false);
}
}
アクティビティに「A」フラグメントを表示することを忘れないでください。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content, new SimpleFragmentA())
.commit();
}
ソース: https://github.com/mikescamell/shared-element-transitions