ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] Shared Elements Transition
    프로그래밍/Android 2019. 1. 28. 09:55

     

    이번 포스팅은 Shared Elements Transition에 대한 내용입니다.

    거두절미 하고 바로 시작하도록 하겠습니다.!

     


     

    Shared Elements Transition?

     

    기존에는 화면 전환 시에 좌우로 넘겨지는 듯한 효과나 Fade 효과를 이용하는 방법들이 대부분이었는데요, 오늘은 조금 다른 효과에 대해 얘기하려 합니다.

     

    우선, 결과물을 먼저 볼까요?

     

     

    Shared Elements Transition

     

     

    보이시나요? 사용자에 의해 선택 된 이미지가 다음 화면까지 연결되어 보여지고 있습니다.

    네 바로 오늘 주제인 Shared Elements Transition의 효과인데요, 이렇듯 화면 간에 공유 되는 요소들에 의해서 좀 더 직관적이고 부드러운 연출이 가능해졌습니다.

     

    이번 예제는 지난 포스트의 예제를 이용하여 진행하도록 하겠습니다.

     

    RecyclerView 사용하기

    https://re-build.tistory.com/42

     

     

    TransitionName 지정하기

    먼저, 화면 간의 공유에 사용 할 요소에 transitionName을 지정해주어야 합니다.

     

    custom_album_item.xml

     

     

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:id="@+id/layout_album_panel"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:orientation="vertical">

     

        <ImageView

            android:id="@+id/img_thumb"

            android:layout_width="match_parent"

            android:layout_height="150dp"

            android:scaleType="centerCrop"

            android:transitionName="pair_thumb" />

     

        <LinearLayout

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:orientation="vertical"

            android:paddingBottom="5dp"

            android:paddingTop="5dp">

     

            <TextView

                android:id="@+id/txt_title"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:textColor="#ffffff"

                android:textSize="16dp" />

     

            <TextView

                android:id="@+id/txt_artist"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:textColor="#8e8e8e"

                android:textSize="14dp" />

        </LinearLayout>

    </LinearLayout>

     

    이어서 화면 전환에 후에 보여질 레이아웃을 꾸며 보겠습니다.

     

    activity_detail.xml

     

     

    <?xml version="1.0" encoding="utf-8"?>

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"

        xmlns:app="http://schemas.android.com/apk/res-auto"

        xmlns:tools="http://schemas.android.com/tools"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:background="#000000"

        android:overScrollMode="never"

        tools:context="rebuild.com.SharedElementsTransitions.Activity.DetailActivity">

     

        <LinearLayout

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            android:gravity="center_horizontal"

            android:orientation="vertical"

            android:paddingLeft="26dp"

            android:paddingRight="26dp">

     

            <ImageView

                android:id="@+id/btn_back"

                android:layout_width="24dp"

                android:layout_height="24dp"

                android:layout_gravity="left"

                android:layout_marginTop="20dp"

                android:src="@drawable/ic_back" />

     

            <ImageView

                android:id="@+id/img_thumb"

                android:layout_width="250dp"

                android:layout_height="250dp"

                android:layout_marginTop="20dp"

                android:scaleType="centerCrop"

                android:transitionName="pair_thumb" />

     

            <TextView

                android:id="@+id/txt_title"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:layout_marginTop="16dp"

                android:textColor="#8e8e8e"

                android:textSize="22dp"

                android:textStyle="bold" />

     

            <TextView

                android:id="@+id/txt_artist"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:textColor="#ffffff"

                android:textSize="16dp" />

     

            <LinearLayout

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:layout_marginTop="5dp">

     

                <TextView

                    android:id="@+id/txt_date"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:textColor="#8e8e8e"

                    android:textSize="13dp" />

     

                <TextView

                    android:id="@+id/txt_type"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:layout_marginLeft="5dp"

                    android:textColor="#8e8e8e"

                    android:textSize="13dp" />

            </LinearLayout>

     

            <TextView

                android:id="@+id/txt_introduce"

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:layout_gravity="left"

                android:layout_marginTop="20dp"

                android:textColor="#8e8e8e"

                android:textSize="13dp" />

     

            <RelativeLayout

                android:layout_width="match_parent"

                android:layout_height="wrap_content">

     

                <android.support.v7.widget.RecyclerView

                    android:id="@+id/rcc_song"

                    android:layout_width="match_parent"

                    android:layout_height="wrap_content"

                    android:layout_marginBottom="20dp"

                    android:layout_marginTop="20dp" />

            </RelativeLayout>

        </LinearLayout>

    </ScrollView>

     

    작성 시에 주의 하실 점은 공유 되는 요소 간의 transitionName은 동일한 이름으로 지정하셔야 합니다.

     

     

    Shared Elements Transition 사용하기

    이제 화면 전환 시에 공유되는 요소들에 어떻게 애니메이션을 적용하는지 살펴보도록 하겠습니다.

     

    MainActivity.java

     

     

    public class MainActivity extends AppCompatActivity implements AlbumAdapter.OnItemClickListener {

     

        @Override

        public void onItemClick(View view, AlbumVO albumVO) {

            Intent intent = new Intent(MainActivity.this, DetailActivity.class);

            intent.putExtra("albumVO", albumVO);

     

            View thumbView = view.findViewById(R.id.img_thumb);

            Pair<View, String> pair_thumb = Pair.create(thumbView, thumbView.getTransitionName());

            ActivityOptionsCompat optionsCompat = 

                        ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, pair_thumb);

     

            startActivity(intent, optionsCompat.toBundle());

        }

    }

     

    전달 받은 View와 앞서 지정했던 transitionName을 묶어 Pair 라는 클래스에 담았습니다. 여기서 Pair<F, S>는 데이터를 좀 더 쉽게 전달하기 위한 컨테이너의 역할을 한다고 보시면 되겠습니다.

     

    이어서, ActionOptionsCompat의 makeSceneTransitionAnimation(Activity, Pair<F, S> ... SharedElements)를 통해 애니메이션을 생성하였는데요, 예제에서는 ImageView에 대해서만 지정 하였지만, 여러개의 Pair를 생성하여 등록하셔도 무방합니다. 단! 너무 많은 사용은 오히려 앱이 조잡해 보일 수 있으니 적당히 사용하시길 권장드립니다. 과유불급.!

     

    그럼 이제, 전환 된 Activity에서 넘겨 받은 데이터를 세팅하고 반대로 다시 이전의 Activity로 돌아올 때의 애니메이션 효과 또한 적용해 보도록 하겠습니다.

     

    DetailActivity.java

     

     

    public class DetailActivity extends AppCompatActivity implements View.OnClickListener {

        private Context mContext;

        private AlbumVO albumVO;

     

        private ImageView btn_back;

        private ImageView img_thumb;

        private TextView txt_title;

        private TextView txt_artist;

        private TextView txt_date;

        private TextView txt_type;

        private TextView txt_introduce;

        private RecyclerView rcc_song;

     

        @Override

        public void onEnterAnimationComplete() {

            super.onEnterAnimationComplete();

            setInit();

        }

     

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_detail);

            mContext = this;

     

            getData();

        }

     

        private void getData() {

            Intent intent = getIntent();

            albumVO = (AlbumVO) intent.getSerializableExtra("albumVO");

        }

     

        private void setInit() {

            btn_back = (ImageView) findViewById(R.id.btn_back);

            btn_back.setOnClickListener(this);

            img_thumb = (ImageView) findViewById(R.id.img_thumb);

            Glide.with(mContext)

                    .load(albumVO.getThumb())

                    .into(img_thumb);

     

            txt_title = (TextView) findViewById(R.id.txt_title);

            txt_title.setText(albumVO.getTitle());

            txt_artist = (TextView) findViewById(R.id.txt_artist);

            txt_artist.setText(albumVO.getArtist());

            txt_date = (TextView) findViewById(R.id.txt_date);

            txt_date.setText(albumVO.getDate());

            txt_type = (TextView) findViewById(R.id.txt_type);

            txt_type.setText(albumVO.getType());

            txt_introduce = (TextView) findViewById(R.id.txt_introduce);

            txt_introduce.setText(albumVO.getIntroduce());

            rcc_song = (RecyclerView) findViewById(R.id.rcc_song);

            RecyclerView.LayoutManager mLayoutManager = 

                                             new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false);

            rcc_song.setLayoutManager(mLayoutManager);

            rcc_song.setNestedScrollingEnabled(false);

            SongAdapter mSongAdapter = new SongAdapter(mContext, albumVO.getSong());

            rcc_song.setAdapter(mSongAdapter);

        }

     

        @Override

        public void onClick(View v) {

            switch (v.getId()) {

                case R.id.btn_back:

                    supportFinishAfterTransition();

                    break;

            }

        }

    }

     

    받아온 데이터들을 세팅하는 부분과 RecyclerView에 대한 부분은 여기서는 생략하도록 하겠습니다. 

     

    주의 깊게 보셔야 할 부분은 굵게 표시된 onEnterAnimationComplete()인데요, 메서드 이름 그대로 진입 애니메이션이 끝난 시점에 호출 됩니다. 예제에서는 여기서 받아온 데이터를 처리하도록 하였지만, 필요에 따라 생략하셔도 무방합니다. onCreate()와 onEnterAnimationComplete()에서 setInit() 메서드를 호출해가며 차이를 확인해보시기 바랍니다.

     

    그 다음으로, 되돌아가기 버튼 클릭 시의 처리는 아주 간단하게 한 줄로 해결이 가능합니다. supportFinishAfterTransition()만 호출 해주시면 되는데요, 이것도 이름 그대로 해당 Activity를 finish() 함과 동시에 Transition 애니메이션을 동작하도록 지원하고 있습니다.

     

     

    여기까지 준비된 내용이 끝났습니다.

    내용이 길어 보이지만 개념적인 부분은 아주 간단하니, 한번 이해하신다면 다른 곳에 쉽게 적용하실 수 있으실 거라고 생각합니다.

    그럼 이만 포스팅을 마치겠습니다.

     


    벌써 1월도 끝나가네요.. 포스팅도 나름대로 열심히 한다고 하는데 부족함을 많이 느껴지네요.

    다음 포스팅은 설 지나고 나서 쓰게 될 것 같습니다. 좀 더 많은 준비를 한 후에 뵙도록 하겠습니다. 모두들 즐거운 설 보내시길 바랍니다,!

     

     

     
     
     

     

Designed by Tistory.