Search code examples
androidandroid-animationandroid-tablayout

How to animate overlay an edit-box on tab-layout on android?


I wanted to achieve this animation, which is the search edit box overlays the tab-layout, I must tell that I tried this code on the parent layout android:animateLayoutChanges="true" and set the tab-layout visibility to View.GONE but it just animates the tab moving up, not the search box overlays tab-layout.

enter image description here


Solution

  • I have made a quick dummy app that looks like yours, and tried to achieve what you have shown in your animation. See the effect below (you can make it more smooth and elegant) :

    enter image description here

    Its a bit tricky way of doing, the way I have done. I post my whole code here :

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.pabhinav.testapp3">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name"
                android:screenOrientation="portrait"
                android:theme="@style/AppTheme.NoActionBar">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    


    MainActivity.java

    package com.pabhinav.testapp3;
    
    import android.os.Bundle;
    import android.support.design.widget.TabLayout;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentPagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.support.v7.app.AppCompatActivity;
    import android.util.DisplayMetrics;
    import android.util.TypedValue;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.AnimationSet;
    import android.view.animation.LinearInterpolator;
    import android.view.animation.ScaleAnimation;
    import android.view.animation.TranslateAnimation;
    import android.widget.EditText;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    
    import static com.pabhinav.testapp3.R.id.container;
    
    public class MainActivity extends AppCompatActivity implements PlaceholderFragment.OnSearchBoxClick{
    
        /**
         * The {@link android.support.v4.view.PagerAdapter} that will provide
         * fragments for each of the sections. We use a
         * {@link FragmentPagerAdapter} derivative, which will keep every
         * loaded fragment in memory. If this becomes too memory intensive, it
         * may be best to switch to a
         * {@link android.support.v4.app.FragmentStatePagerAdapter}.
         */
        private SectionsPagerAdapter mSectionsPagerAdapter;
    
        /**
         * The {@link ViewPager} that will host the section contents.
         */
        private ViewPager mViewPager;
    
        /**
         * Search Box in activity.
         */
        private RelativeLayout dummySearchBox;
    
        private LinearLayout topSearchBox;
    
        /**
         * Overlay View appears when search box is clicked.
         */
        private View overlay;
    
        /**
         * Back button image view for top search box
         */
        private ImageView backButtonSearchBox;
    
        /**
         * PlaceHolderFragment saved only for second tab,
         * which has search box.
         */
        private PlaceholderFragment placeholderFragment;
    
        private float xDelta, yDelta;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Create the adapter that will return a fragment for each of the three
            // primary sections of the activity.
            mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
            getWindow().setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
            overlay = findViewById(R.id.overlay_whole_page);
            backButtonSearchBox = (ImageView)findViewById(R.id.search_icon);
    
            // Consume touch event, so that it does not pass to parent views.
            // This is done to block swipe events of tab layout, once search
            // box is clicked.
            overlay.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return true;
                }
            });
    
            // TabLayout and ViewPager.
            final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
            mViewPager = (ViewPager) findViewById(container);
            dummySearchBox = (RelativeLayout)findViewById(R.id.dummy_search_box);
            topSearchBox = (LinearLayout)findViewById(R.id.top_search_box);
    
            // Set up the ViewPager with the sections adapter.
            mViewPager.setAdapter(mSectionsPagerAdapter);
            mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
    
                @Override
                public void onPageSelected(int position) {
                    for (int i = 0; i < tabLayout.getTabCount(); i++) {
                        if(i == position){
                            tabLayout.getTabAt(i).setIcon(getTabIconHighlighted(i));
                        } else {
                            tabLayout.getTabAt(i).setIcon(getTabIconUnhighlighted(i));
                        }
                    }
                }
    
                @Override
                public void onPageScrollStateChanged(int state) {}
            });
    
            // Setup viewpager with tablayout and also set up icons of each tabs :
            tabLayout.setupWithViewPager(mViewPager);
            for(int i = 0; i<tabLayout.getTabCount(); i++){
    
                // Set first tab highlighted :
                if(i == 0){
                    tabLayout.getTabAt(i).setIcon(getTabIconHighlighted(i));
                } else {
                    tabLayout.getTabAt(i).setIcon(getTabIconUnhighlighted(i));
                }
            }
    
            // Back Button in top search box clicked.
            backButtonSearchBox.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    overlay.setVisibility(View.INVISIBLE);
                    dummySearchBox.setVisibility(View.VISIBLE);
                    topSearchBox.setVisibility(View.INVISIBLE);
    
                    AnimationSet animSet = new AnimationSet(true);
                    animSet.setFillAfter(false);
                    animSet.setDuration(150);
                    animSet.setInterpolator(new LinearInterpolator());
                    TranslateAnimation translate = new TranslateAnimation(-xDelta, 0, -yDelta, 0);
                    animSet.addAnimation(translate);
                    ScaleAnimation scale = new ScaleAnimation(1.2f, 1f, 1.2f, 1f);
                    animSet.addAnimation(scale);
                    dummySearchBox.startAnimation(animSet);
                    animSet.setAnimationListener(new Animation.AnimationListener() {
                        @Override
                        public void onAnimationStart(Animation animation) {
    
                        }
    
                        @Override
                        public void onAnimationEnd(Animation animation) {
                            placeholderFragment.showSearchLayout();
                            dummySearchBox.setVisibility(View.INVISIBLE);
                        }
    
                        @Override
                        public void onAnimationRepeat(Animation animation) {
    
                        }
                    });
                }
            });
        }
    
        private int getTabIconUnhighlighted(int position){
            switch (position){
                case 0 : return R.drawable.ic_home_black_24dp;
                case 1 : return R.drawable.ic_search_black_24dp;
                case 2 : return R.drawable.ic_heart_black_24dp;
                case 3 : return R.drawable.ic_view_headline_black_24dp;
            }
            return -1;
        }
    
        private int getTabIconHighlighted(int position){
            switch(position){
                case 0 : return R.drawable.ic_home_highlighted_24dp;
                case 1 : return R.drawable.ic_search_highlighted_24dp;
                case 2 : return R.drawable.ic_heart_highlighted_24dp;
                case 3 : return R.drawable.ic_view_headline_highlighted_24dp;
            }
            return -1;
        }
    
        /**
         * This event is when search box from fragment is clicked,
         * need to animate the search box present in activity
         * to reach the top of activity display.
         */
        @Override
        public void onClick() {
            dummySearchBox.setVisibility(View.VISIBLE);
            dummySearchBox.clearFocus();
            ((EditText)findViewById(R.id.search_edit_text)).clearFocus();
            performAnimation(dummySearchBox);
        }
    
        public void performAnimation(final RelativeLayout dummySearchBox){
    
            if(xDelta == 0 && yDelta == 0){
                DisplayMetrics dm = new DisplayMetrics();
                getWindowManager().getDefaultDisplay().getMetrics(dm);
                int[] originalPos = new int[2];
                dummySearchBox.getLocationOnScreen(originalPos);
    
                xDelta = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 18, getResources().getDisplayMetrics());
                yDelta = originalPos[1] - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12, getResources().getDisplayMetrics());;
            }
    
            AnimationSet animSet = new AnimationSet(true);
            animSet.setFillAfter(false);
            animSet.setDuration(200);
            animSet.setInterpolator(new LinearInterpolator());
            TranslateAnimation translate = new TranslateAnimation( 0, -1*xDelta, 0, -1*yDelta);
            animSet.addAnimation(translate);
            ScaleAnimation scale = new ScaleAnimation(1f, 1.15f, 1f, 1.15f);
            animSet.addAnimation(scale);
            dummySearchBox.startAnimation(animSet);
            animSet.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
    
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
    
                    topSearchBox.setVisibility(View.VISIBLE);
                    dummySearchBox.setVisibility(View.INVISIBLE);
                    overlay.setVisibility(View.VISIBLE);
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
    
                }
            });
        }
    
        /**
         * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
         * one of the sections/tabs/pages.
         */
        public class SectionsPagerAdapter extends FragmentPagerAdapter {
    
            /**
             * The fragment argument representing the section number for this
             * fragment.
             */
            public static final String ARG_SECTION_NUMBER = "section_number";
    
            public SectionsPagerAdapter(FragmentManager fm) {
                super(fm);
            }
    
            @Override
            public Fragment getItem(int position) {
                // getItem is called to instantiate the fragment for the given page.
                // Return a PlaceholderFragment.
                PlaceholderFragment placeholderFragment = new PlaceholderFragment();
                placeholderFragment.setOnSearchBoxClick(MainActivity.this);
                Bundle args = new Bundle();
                args.putInt(ARG_SECTION_NUMBER, position + 1);
                placeholderFragment.setArguments(args);
                if(position == 1){
                    MainActivity.this.placeholderFragment = placeholderFragment;
                }
                return placeholderFragment;
            }
    
            @Override
            public int getCount() {
                // Show 4 total pages.
                return 4;
            }
        }
    }
    

    PlaceholderFragment.java

    package com.pabhinav.testapp3;
    
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    /**
     * @author pabhinav
     */
    
    public class PlaceholderFragment extends Fragment {
    
        private LinearLayout searchLayout;
    
        public PlaceholderFragment() {
        }
    
        private OnSearchBoxClick onSearchBoxClick;
        public void setOnSearchBoxClick(OnSearchBoxClick onSearchBoxClick){
            this.onSearchBoxClick = onSearchBoxClick;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            int sectionNumber = getArguments().getInt(MainActivity.SectionsPagerAdapter.ARG_SECTION_NUMBER);
            View rootView = inflater.inflate((sectionNumber == 2) ? R.layout.fragment_search : R.layout.fragment_main, container, false);
            if(sectionNumber != 2) {
                TextView textView = (TextView) rootView.findViewById(R.id.section_label);
                textView.setText(getString(R.string.section_format, sectionNumber));
            } else {
    
                // Its the fragment with search box :
                TextView searchText = (TextView) rootView.findViewById(R.id.search_text);
                ImageView searchIcon = (ImageView)rootView.findViewById(R.id.search_icon);
                searchLayout = (LinearLayout)rootView.findViewById(R.id.search_linear_layout);
    
                // Need to do transition when clicked on any of the search box elements :
                View.OnClickListener clickListener = new View.OnClickListener(){
                    @Override
                    public void onClick(View v) {
                        searchLayout.setVisibility(View.INVISIBLE);
                        if(onSearchBoxClick != null)
                            onSearchBoxClick.onClick();
                    }
                };
                searchText.setOnClickListener(clickListener);
                searchLayout.setOnClickListener(clickListener);
                searchIcon.setOnClickListener(clickListener);
            }
            return rootView;
        }
    
        public void showSearchLayout(){
            searchLayout.setVisibility(View.VISIBLE);
        }
    
        public interface OnSearchBoxClick{
            public void onClick();
        }
    }
    


    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context="com.pabhinav.testapp3.MainActivity">
    
        <android.support.design.widget.TabLayout
            android:layout_marginTop="8dp"
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
        <!-- Top Search Box -->
        <!-- Only appears when search box is clicked -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:id="@+id/top_search_box"
            android:visibility="invisible"
            android:orientation="horizontal">
    
            <RelativeLayout
                android:layout_gravity="center"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@android:color/white">
    
                <ImageView
                    android:gravity = "center"
                    android:layout_width="52dp"
                    android:paddingLeft="24dp"
                    android:paddingRight="8dp"
                    android:id="@+id/search_icon"
                    android:layout_height="match_parent"
                    android:src="@drawable/ic_arrow_back_black_24dp"/>
    
                <EditText
                    android:layout_toEndOf="@+id/search_icon"
                    android:hint="@string/search_soundcloud"
                    android:textSize="18sp"
                    android:background="@android:color/transparent"
                    android:textColorHint="#B3B3B3"
                    android:layout_margin="4dp"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
    
            </RelativeLayout>
    
        </LinearLayout>
    
        <!-- Dummy container for search box -->
        <!-- This will do transition from its location to top_search_box location -->
        <RelativeLayout
            android:id="@+id/dummy_search_box"
            android:layout_width="match_parent"
            android:layout_below="@+id/tabs"
            android:visibility="invisible"
            android:layout_height="wrap_content"
            android:padding="16dp">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="56dp"
                android:id="@+id/search_linear_layout_dummy"
                android:orientation="horizontal">
    
                <RelativeLayout
                    android:layout_gravity="center"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_margin="5dp"
                    android:background="@android:color/white"
                    android:elevation="2dp"
                    android:translationZ="2dp">
    
                    <ImageView
                        android:gravity = "center"
                        android:layout_width="20dp"
                        android:layout_marginStart="16dp"
                        android:id="@+id/search_icon_dummy"
                        android:layout_height="match_parent"
                        android:src="@drawable/ic_search_light_black_24dp"/>
    
                    <EditText
                        android:id="@+id/search_edit_text"
                        android:layout_toEndOf="@+id/search_icon_dummy"
                        android:hint="@string/search_soundcloud"
                        android:textSize="16sp"
                        android:background="@android:color/transparent"
                        android:textColorHint="#B3B3B3"
                        android:layout_margin="4dp"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent" />
    
                </RelativeLayout>
    
            </LinearLayout>
    
        </RelativeLayout>
    
    
        <android.support.v4.view.ViewPager
            android:layout_below="@+id/tabs"
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    
        <!-- Dummy overlay over whole page, More things can be added like listview
             which displays result of searched text -->
        <View
            android:id="@+id/overlay_whole_page"
            android:layout_below="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"
            android:background="#72000000" />
    
        <!-- Dummy shadow below tablayout -->
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_below="@+id/tabs"
            android:background="#42000000" />
    
    
    
    </RelativeLayout>
    

    fragment_search.xml

    <RelativeLayout
        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:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.pabhinav.testapp3.MainActivity$PlaceholderFragment">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="56dp"
            android:id="@+id/search_linear_layout"
            android:orientation="horizontal">
    
            <RelativeLayout
                android:layout_gravity="center"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"
                android:background="@android:color/white"
                android:elevation="2dp"
                android:translationZ="2dp">
    
                <ImageView
                    android:gravity = "center"
                    android:layout_width="20dp"
                    android:layout_marginStart="16dp"
                    android:id="@+id/search_icon"
                    android:layout_height="match_parent"
                    android:src="@drawable/ic_search_light_black_24dp"/>
    
                <TextView
                    android:id="@+id/search_text"
                    android:layout_toEndOf="@+id/search_icon"
                    android:text="@string/search_soundcloud"
                    android:gravity="center_vertical"
                    android:textColor="#B3B3B3"
                    android:textSize="16sp"
                    android:layout_margin="4dp"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
    
            </RelativeLayout>
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/suggested_stations"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="56dp"
            android:textSize="18sp"
            android:layout_below="@+id/search_linear_layout"
            android:text = "@string/suggested_stations"/>
    
        <LinearLayout
            android:layout_below="@+id/suggested_stations"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <ImageView
                android:layout_width="0dp"
                android:layout_height="240dp"
                android:src="@drawable/image_1"
                android:layout_weight="1"/>
    
            <ImageView
                android:layout_marginStart="16dp"
                android:layout_width="0dp"
                android:layout_height="240dp"
                android:src="@drawable/image_2"
                android:layout_weight="1"/>
    
        </LinearLayout>
    
    </RelativeLayout>
    


    Download the whole project from here : https://drive.google.com/file/d/0B_Mi44NWLWmyNFNkeHJ6cVBLTTg/view?usp=sharing

    Hope it helps !