Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 386
Shaheen Zahedi Avatar asked Nov 03 '16 19:11

Shaheen Zahedi


1 Answers

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 !

like image 175
Abhinav Puri Avatar answered Nov 14 '22 22:11

Abhinav Puri