Foggy day

Android(Java, kotlin) - Appbar Animation with ViewPager inside Fragment 본문

Android

Android(Java, kotlin) - Appbar Animation with ViewPager inside Fragment

jinhan38 2020. 12. 29. 01:03

 

 

When making app, we mostly use viewpager and tablayout, and appbar. Animation showing or hiding appbar in activity is not too difficult. But, Sometimes a slightly complicated UI bothers us. For example, there is a fragment A in the activity, and the AppBar, tablayout, and ViewPager ars in the A fragment. The VewPapger has fragments B, C, and D. In this structure what i want to do is an animation that shows and hides fragment B's appBar when scrolling up and down fragments B and C, not D. Of coures, the viewpager swipe functions show also work.

 

This arcticle is a sample that implements the above example.

If you know about databinding, appbar, viewpager, and tablayout, it will help you understand this article. It does not describe in detail the databinding, appbar, viewpager, and tablaout.

 

 

Video preview

 

 

 

 

 


 

 

 

Let's get started.

 

 

First of all, I will show you the package structure. I used the following classes.

 

 

 

 

 

 

 

1. activity_app_bar_hide_animation.xml

Here, there is only the framelayout that will be the container of the fragment. 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/fragmentContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

 

2. AppBarHideAnimationActivity

Hide actionbar and commit the fragment to be created next.

※ It you have a nestedScrollview in this layout, Appbar show/hide function will be not working.

public class AppBarHideAnimationActivity extends AppCompatActivity {

    private ActivityAppBarHideAnimationBinding binding;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getSupportActionBar().hide();
        binding = ActivityAppBarHideAnimationBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        Fragment fragment = new AppBarHideAnimationFragment();
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragmentContainer, fragment);
        fragmentTransaction.commit();

    }
}

 

 

3. app_bar_hide_animation_fragment.xml

Here, there are appbarlayout, viewpager2 and tablayout. The remarkable part is that CoordinatorLayout cover the whole. For appbar behavior, it is absolutely necessary. Also, Don;t forget the code below.

 

  • app:layout_scrollFlags="scroll|enterAlways|snap"
  • app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_scrollFlags="scroll|enterAlways|snap">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="It is Toolbar"
                    android:textColor="@color/white"
                    android:textSize="17dp" />

            </androidx.appcompat.widget.Toolbar>

            <com.google.android.material.tabs.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:background="@color/white"
                app:tabIndicatorColor="#9C27B0"
                app:tabIndicatorHeight="5dp"
                app:tabMode="fixed"
                app:tabRippleColor="@android:color/transparent"
                app:tabSelectedTextColor="#9C27B0">

                <com.google.android.material.tabs.TabItem
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="First" />

                <com.google.android.material.tabs.TabItem
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Second" />

                <com.google.android.material.tabs.TabItem
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Third" />

            </com.google.android.material.tabs.TabLayout>

        </com.google.android.material.appbar.AppBarLayout>


        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

</LinearLayout>

 

4. ViewPagerAdapter

Depending on type of viewpager, the way how to create viewpagerAdapter is different.

In this article, I used this.

public class ViewPagerAdapter extends FragmentStateAdapter {

    private String[] dataList;

    public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity, String[] dataList) {
        super(fragmentActivity);
        this.dataList = dataList;
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        Fragment fragment;
        switch (position) {
            case 0:
                fragment = new FirstFragment();
                break;
            case 1:
                fragment = new SecondFragment();
                break;
            case 2:
                fragment = new ThirdFragment();
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + position);
        }
        return fragment;
    }

    @Override
    public int getItemCount() {
        return dataList.length;
    }


}

 

 

5. AppBarHideAnimationFragment

Connect viewpager, viewpagerAdapter, and tablayout.

public class AppBarHideAnimationFragment extends Fragment {

    private AppBarHideAnimationFragmentBinding binding;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        binding = AppBarHideAnimationFragmentBinding.inflate(getLayoutInflater());

        String[] dataList = new String[]{"First", "Second", "Third"};

        ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getActivity(), dataList);
        binding.viewPager.setAdapter(viewPagerAdapter); // note : It is ViewPager2, Not Viewpager

        //This is from official google document.
        //If you want know more about this, please refer to this link :
        //https://developer.android.com/guide/navigation/navigation-swipe-view-2?hl=ko
        new TabLayoutMediator(binding.tabLayout, binding.viewPager, ((tab, position) -> tab.setText("OBJECT " + (position + 1))
        )).attach();

        return binding.getRoot();

    }
}

 

6. fragment_first.xml

This xml has NestedScrollview.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/gray"
    tools:context=".viewPager.depth.fragment.FirstFragment">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fillViewport="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 1"
                android:textColor="@color/white"
                android:textSize="30dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 2"
                android:textColor="@color/white"
                android:textSize="30dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 3"
                android:textColor="@color/white"
                android:textSize="30dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 4"
                android:textColor="@color/white"
                android:textSize="30dp" />

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</LinearLayout>

 

class FirstFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_first, container, false)
    }

}

 

 

7. fragment_second.xml

SecondFragment is the same as the FirstFragment. 

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/purple_500"
    tools:context=".viewPager.depth.fragment.SecondFragment">

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 1"
                android:textColor="@color/white"
                android:textSize="30dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 2"
                android:textColor="@color/white"
                android:textSize="30dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 3"
                android:textColor="@color/white"
                android:textSize="30dp" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:gravity="center"
                android:text="Scroll Animation 4"
                android:textColor="@color/white"
                android:textSize="30dp" />

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>


</FrameLayout>
class SecondFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_second, container, false)
    }


}

 

 

8. fragment_third.xml

ThridFragment only changed the background color. The Third doesn't have scrollview. So animation appbar isn't working

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/teal_200"
    tools:context=".viewPager.depth.fragment.ThirdFragment">

</FrameLayout>
class ThirdFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_third, container, false)
    }

}

 

 

All the necessary work is done. It should work. you can toolbar visibility by scrolling OBJECT1, OBJECT2. But OBJECT3 not have scrollview, so can not controll toolbar visibility.

If you have any questions, please leave a comment.