2
\$\begingroup\$

I am currently making an application where the user will launch the app and the first this we see is the app logo fade in at the center of the screen. After about a second, the logo will translate up and the rest of the content will appear. I currently have a lot of code and wanted to know if this is the most efficient way of doing what I am doing. It seems like a lot of code for 3 animations.

search_logo_animation.xml:

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">

    <alpha
        android:duration="800"
        android:fromAlpha="0.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1.0" />

    <translate
        android:duration="800"
        android:fillAfter="true"
        android:fromYDelta="0%p"
        android:startOffset="2000"
        android:toYDelta="-30%p" />

</set>

search_container_animation.xml:

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">

    <alpha
        android:duration="800"
        android:fromAlpha="0.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1.0" />

</set>

search_button_animation.xml:

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">

    <alpha
        android:duration="800"
        android:fromAlpha="0.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1.0" />

</set>

search.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/search"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary"
    tools:context=".Search">

    <ImageView
        android:id="@+id/searchLogo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:contentDescription="@string/app_logo"
        android:visibility="invisible"
        android:src="@mipmap/ic_logo" />

    <LinearLayout
        android:id="@+id/searchContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="@dimen/search_container_margin_left"
        android:layout_marginStart="@dimen/search_container_margin_left"
        android:layout_marginRight="@dimen/search_container_margin_right"
        android:layout_marginEnd="@dimen/search_container_margin_right"
        android:paddingLeft="@dimen/search_container_padding_left"
        android:paddingStart="@dimen/search_container_padding_left"
        android:paddingRight="@dimen/search_container_padding_right"
        android:paddingEnd="@dimen/search_container_padding_right"
        android:paddingTop="@dimen/search_container_padding_top"
        android:paddingBottom="@dimen/search_container_padding_bottom"
        android:orientation="vertical"
        android:visibility="invisible"
        android:background="@drawable/search_container">

        <LinearLayout
            android:id="@+id/searchMakeContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView
                android:id="@+id/searchMakeLabel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/make" />

            <TextView
                android:id="@+id/searchMakeSelection"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/search_option_margin_left"
                android:layout_marginStart="@dimen/search_option_margin_left"
                android:textSize="@dimen/search_option_text_size"
                android:text="@string/any" />

        </LinearLayout>

        <LinearLayout
            android:id="@+id/searchModelContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/search_option_margin_top"
            android:orientation="vertical">

            <TextView
                android:id="@+id/searchModelLabel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/model" />

            <TextView
                android:id="@+id/searchModelSelection"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/search_option_margin_left"
                android:layout_marginStart="@dimen/search_option_margin_left"
                android:textSize="@dimen/search_option_text_size"
                android:text="@string/any" />

        </LinearLayout>

    </LinearLayout>

    <Button
        android:id="@+id/searchButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/searchContainer"
        android:layout_marginLeft="@dimen/search_button_margin_left"
        android:layout_marginStart="@dimen/search_button_margin_left"
        android:layout_marginRight="@dimen/search_button_margin_right"
        android:layout_marginEnd="@dimen/search_button_margin_right"
        android:layout_marginTop="@dimen/search_button_margin_top"
        android:text="@string/search_listings"
        android:textColor="@android:color/white"
        android:textAllCaps="false"
        android:visibility="invisible"
        android:background="@drawable/search_button_selector" />

</RelativeLayout>

Search.java:

public class Search extends AppCompatActivity implements AnimationListener {

    ImageView searchLogo;

    LinearLayout searchContainer;

    Button searchButton;

    Animation searchLogoAnimation, searchContainerAnimation, searchButtonAnimation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search);

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

        searchContainer = (LinearLayout) findViewById(R.id.searchContainer);

        searchButton = (Button) findViewById(R.id.searchButton);

        searchLogoAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.search_logo_animation);
        searchLogoAnimation.setAnimationListener(this);

        searchContainerAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.search_container_animation);
        searchContainerAnimation.setAnimationListener(this);

        searchButtonAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.search_button_animation);
        searchButtonAnimation.setAnimationListener(this);

        searchLogo.startAnimation(searchLogoAnimation);
    }

    @Override
    public void onAnimationEnd(Animation animation) {
        if (animation == searchLogoAnimation) {
            searchContainer.startAnimation(searchContainerAnimation);
            searchButton.startAnimation(searchButtonAnimation);
        }
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }

    @Override
    public void onAnimationStart(Animation animation) {

    }

}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

First of all you could define styles for your layout search.xml files in your /res/values/styles.xml:

 <style name="LayoutStyleWide">        
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
 </style>

 <style name="TextViewSelectionStyle" parent="@style/LayoutStyleWide">
    <item name="android:layout_marginLeft="@dimen/search_option_margin_left"</item>
    <item name="android:layout_marginStart="@dimen/search_option_margin_left"</item>
    <item name="android:textSize="@dimen/search_option_text_size"</item>
    <item name="android:text="@string/any"</item>
 </style>

etc.

Combine anything that views have in common in styles.

Part of your layout search.xml file then could look like this:

    <LinearLayout
        android:id="@+id/searchMakeContainer"
        style="@style/LayoutStyleWide"
        android:orientation="vertical">

        <TextView
            android:id="@+id/searchMakeLabel"
            style="@style/LayoutStyleWide"
            android:text="@string/make" />

        <TextView
            android:id="@+id/searchMakeSelection"
            style="@style/TextViewSelectionStyle"/>

    </LinearLayout>

    <LinearLayout
        android:id="@+id/searchModelContainer"
        style="@style/LayoutStyleWide"
        android:layout_marginTop="@dimen/search_option_margin_top"
        android:orientation="vertical">

        <TextView
            android:id="@+id/searchModelLabel"
            style="@style/LayoutStyleWide"
            android:text="@string/model" />

        <TextView
            android:id="@+id/searchModelSelection"
            style="@style/TextViewSelectionStyle"
            android:textSize="@dimen/search_option_text_size"/>

    </LinearLayout>

About your Java code:

Personally I like to keep my onCreate method clean and readable, so I`d separate these lines into methods:

    private void initializeViews() {
        searchLogo = (ImageView) findViewById(R.id.searchLogo);
        searchContainer = (LinearLayout) findViewById(R.id.searchContainer);
        searchButton = (Button) findViewById(R.id.searchButton);
        accelerate = new AccelerateInterpolator();
    }

Then you can replace your XML animations with these methods, which are more dynamic:

    private void animateAlpha(View view, float toAlpha,
       int duration, Interpolator interpolator) {
        view.animate().alpha(toAlpha).setDuration(duration).setInterpolator(interpolator);
    }

    private void animateTranslation(View view, float translateToX, 
      float translateToY, int duration, Interpolator interpolator, int startDelay){
        view.animate()
            .translationY(translateToY)
            .translationX(translateToX)
            .setDuration(duration)
            .setInterpolator(interpolator)
            .setStartDelay(startDelay)
            .setListener(this);
    }

This way you can extend and reuse the animation methods easily, and you can get rid of all your animation XML files because you are using ViewPropertyAnimator.

Since you are only using AccelerateInterpolator you can define it as a field too.

Your search.java then could look like this:

public class Search extends AppCompatActivity implements AnimationListener {

    ImageView searchLogo;
    LinearLayout searchContainer;
    Button searchButton;
    Interpolator accelerate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search);

        initializeViews();

        animateAlpha(searchLogo, 1.0f, 800, accelerate);
        animateTranslation(searchLogo, 0, -30, 800, accelerate, 2000); // I'll leave it to you to get the -30% ;) 

    }

    @Override
    public void onAnimationEnd(Animation animation) {
        animateAlpha(searchContainer, 1.0f, 800, accelerate);
        animateAlpha(searchButton, 1.0f, 800, accelerate);            
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }

    @Override
    public void onAnimationStart(Animation animation) {

    }

    private void initializeViews() {
        searchLogo = (ImageView) findViewById(R.id.searchLogo);
        searchContainer = (LinearLayout) findViewById(R.id.searchContainer);
        searchButton = (Button) findViewById(R.id.searchButton);
        accelerate = new AccelerateInterpolator();
    }

    private void animateAlpha(View view, float toAlpha,
       int duration, Interpolator interpolator) {
        view.animate().alpha(toAlpha).setDuration(duration).setInterpolator(interpolator);
    }

    private void animateTranslation(View view, float translateToX, 
      float translateToY, int duration, Interpolator interpolator, int startDelay){
        view.animate()
            .translationY(translateToY)
            .translationX(translateToX)
            .setDuration(duration)
            .setInterpolator(interpolator)
            .setStartDelay(startDelay)
            .setListener(this);
    }
}

But after all, it's just a matter of taste...

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.