воскресенье, 4 марта 2012 г.

Android. Анимированные переходы между окнами

Увидев переходы между окнами на iPhone решил сделать что-нибудь такое на Android.
В этой статье расскажу и покажу как сделать анимированные переходы между окнами на Android.
Будут рассмотрены diagonal, zoom, slide-переходы. Все что будет показано в этой статье проверено на Android 2.1 и выше.

Ну начнем.

Как всегда создаем наш проект. Сегодня назову его AndroidTransition.
Прежде всего нам надо добавить в папку res папку anim. Она нужна для наших будущих анимаций. Вот так будет выглядеть структура приложения:


Теперь создадим второе activity. ( в мое случае SecondActivity.java ) Надо же куда-то нам переходить из основного окна :). Для него создадим UI в новом second.xml файле.

Вот такие два файла получатся ( second.xml с некоторыми изменениями ):

SecondActivity.java
 package com.lunevich.android;
  
 import android.app.Activity;  
 import android.content.Intent;  
 import android.os.Bundle;  
 import android.view.View;  
 import android.view.View.OnClickListener;  
 import android.widget.Button;  

 public class SecondActivity extends Activity {  
        
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.second);  
   }  
 }  

second.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   android:layout_width="fill_parent"  
   android:layout_height="fill_parent"  
   android:orientation="vertical"  
   android:background="@android:color/background_light" > 
 
   <Button  
     android:id="@+id/btnBack"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_gravity="center_horizontal"  
     android:layout_marginTop="50px"  
     android:text="BACK" />  

   <TextView  
     android:id="@+id/textView1"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_gravity="center_horizontal"  
     android:layout_margin="40px"  
     android:text="Second View"  
     android:textColor="@android:color/black"  
     android:textAppearance="?android:attr/textAppearanceMedium" />  

 </LinearLayout>  


Теперь изменим наш main.xml файл. Добавим в него 3 кнопки для наших переходов. Выглядеть он будет вот так:

main.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   android:layout_width="fill_parent"  
   android:layout_height="fill_parent"  
   android:orientation="vertical"  
   android:background="#1B9EE0" >  

   <TextView  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_gravity="center_horizontal"  
     android:layout_margin="10px"  
     android:text="@string/hello"  
     android:textColor="@android:color/black" />  

   <Button  
     android:id="@+id/btnZoomTransition"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_gravity="center_horizontal"  
     android:layout_margin="10px"  
     android:text="Zoom Transition" />  
 
   <Button  
     android:id="@+id/btnSlideLeftTransition"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_gravity="center_horizontal"  
     android:layout_margin="10px"  
     android:text="Slide Left Transition" /> 
 
   <Button  
     android:id="@+id/btnDiagonalTransition"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:layout_gravity="center_horizontal"  
     android:layout_margin="10px"  
     android:text="Diagonal Transition" />  

 </LinearLayout>  


Сейчас можно приступить к написанию анимаций для переходов.
Начнем с diagonal-перехода. В нашей папке  anim  создаем 2 xml файла ( diagonal_in.xml и diagonal_out.xml ). Изменяем их так:

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

   <translate  
     xmlns:android="http://schemas.android.com/apk/res/android"  
     android:duration="2000"  
     android:fromXDelta="-100%"  
     android:fromYDelta="-100%"  
     android:toXDelta="0%"  
     android:toYDelta="0%" />  

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

   <translate  
     xmlns:android="http://schemas.android.com/apk/res/android"  
     android:duration="2000"  
     android:fromXDelta="0%"  
     android:fromYDelta="0%"  
     android:toXDelta="-100%"  
     android:toYDelta="-100%" />  

 </set>  


Теперь создадим ещё 2 файла: zoom_in.xml и zoom_out.xml. Они будут отвечать за zoom анимированный переход между окнами. Вот так мы их изменим:

zoom_in.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <set xmlns:android="http://schemas.android.com/apk/res/android" > 
 
   <alpha  
     android:duration="@android:integer/config_mediumAnimTime"  
     android:fromAlpha="0.0"  
     android:interpolator="@android:anim/accelerate_interpolator"  
     android:toAlpha="1.0" />  

 </set>  
zoom_out.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <set xmlns:android="http://schemas.android.com/apk/res/android" > 
 
   <alpha  
     android:duration="@android:integer/config_mediumAnimTime"  
     android:fromAlpha="1.0"  
     android:interpolator="@android:anim/accelerate_interpolator"  
     android:toAlpha="0.0" />  

 </set>  


Добавим в папку anim ещё 4 файла которые будут отвечать за slide-анимацию. ( slide_left_in.xml, slide_left_out.xml, slide_right_in.xml, slide_right_out.xml )

slide_left_in.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <set xmlns:android="http://schemas.android.com/apk/res/android" > 
 
   <translate  
     android:duration="800"  
     android:fromXDelta="100%p"  
     android:toXDelta="0" />  

 </set>  
slide_left_out.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <set xmlns:android="http://schemas.android.com/apk/res/android" > 
 
   <translate  
     android:duration="800"  
     android:fromXDelta="0"  
     android:toXDelta="-100%p" />  

 </set>  
slide_right_in.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <set xmlns:android="http://schemas.android.com/apk/res/android" > 
 
   <translate  
     android:duration="800"  
     android:fromXDelta="-100%p"  
     android:toXDelta="0" />  

 </set>  
slide_right_out.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <set xmlns:android="http://schemas.android.com/apk/res/android" > 
 
   <translate  
     android:duration="800"  
     android:fromXDelta="0"  
     android:toXDelta="100%p" />  

 </set>  


Вот теперь все наши анимированные переходы готовы.
Можем приступить к изменению AndroidTransitionActivity.java и SecondActivity.java файлов.

Файл AndroidTransitionActivity.java изменим вот так:

AndroidTransitionActivity.java
 package com.lunevich.android;
  
 import android.app.Activity;  
 import android.content.Intent;  
 import android.os.Bundle;  
 import android.view.View;  
 import android.view.View.OnClickListener;  
 import android.widget.Button;  

 public class AndroidTransitionActivity extends Activity implements OnClickListener { 
 
   // Перечисление TransitionType создано только для демонстрации нескольких анимаций
   public static enum TransitionType {  
        Zoom, SlideLeft, Diagonal  
   }  
   public static TransitionType transitionType;
  
   private Button btnZoomTransition;  
   private Button btnSlideLeftTransition;  
   private Button btnDiagonalTransition;  
 
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.main);  

     // Регистрируем кнопки и вешаем на них обработчики нажатия
     btnZoomTransition = (Button)findViewById(R.id.btnZoomTransition);  
     btnZoomTransition.setOnClickListener(this);  
     btnSlideLeftTransition = (Button)findViewById(R.id.btnSlideLeftTransition);  
     btnSlideLeftTransition.setOnClickListener(this);  
     btnDiagonalTransition = (Button)findViewById(R.id.btnDiagonalTransition);  
     btnDiagonalTransition.setOnClickListener(this);  
   }  

   public void onClick(View v) {  
        // TODO Auto-generated method stub  
        // Завершаем наше текущее activity
        this.finish(); 

        // С помощью intent переходим во второе окно
        Intent intent = new Intent(this, SecondActivity.class);  
        startActivity(intent);
 
        switch (v.getId()) {  
        case R.id.btnZoomTransition: 
             // Устанавливаем тип нашей анимации
             transitionType = TransitionType.Zoom;  

             // Для AndroidTransitionActivity указываем, 
             // с помощью какой анимации мы будем переходить в другое окно
             overridePendingTransition(R.anim.zoom_in, R.anim.zoom_out);  
             break;  
        case R.id.btnSlideLeftTransition:  
             transitionType = TransitionType.SlideLeft;  
             overridePendingTransition(R.anim.slide_left_in, R.anim.slide_left_out);  
             break;  
        case R.id.btnDiagonalTransition:  
             transitionType = TransitionType.Diagonal;  
             overridePendingTransition(R.anim.diagonal_in, R.anim.diagonal_out);  
             break;  
        }  
   }  
 }  


Измененный SecondActivity.java файл теперь будет выглядеть вот так:

SecondActivity.java
 package com.lunevich.android;  

 import android.app.Activity;  
 import android.content.Intent;  
 import android.os.Bundle;  
 import android.view.View;  
 import android.view.View.OnClickListener;  
 import android.widget.Button;  

 public class SecondActivity extends Activity implements OnClickListener {  

   private Button btnBack;    

   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.second); 
 
     // Регистрируем нашу кнопку back и вешаем на неё обработчик нажатия
     btnBack = (Button)findViewById(R.id.btnBack);  
     btnBack.setOnClickListener(this);  
   } 
 
   public void onClick(View v) {  
        // TODO Auto-generated method stub  
        switch (v.getId()) {  
        case R.id.btnBack:  
             onBackPressed();  
             break;  
        }  
   }  

   @Override  
   public void onBackPressed() { 
 
           // Завершаем наше activity
           this.finish(); 

           // Intent отвечает за переходы между activity, 
           // здесь мы возвращаемся обратно в наше главное окно
           Intent intent = new Intent(this, AndroidTransitionActivity.class);  
           startActivity(intent);  

           // Проверяем с помощью какой анимации мы перешли, по той же анимации и возвращаемся
           if (AndroidTransitionActivity.transitionType == AndroidTransitionActivity.TransitionType.SlideLeft) {  
                // Для SecondActivity устанавливаем анимацию перехода
                overridePendingTransition(R.anim.slide_right_in, R.anim.slide_right_out);  
           } else if (AndroidTransitionActivity.transitionType == AndroidTransitionActivity.TransitionType.Zoom) {  
                overridePendingTransition(R.anim.zoom_in, R.anim.zoom_out);  
           } else if (AndroidTransitionActivity.transitionType == AndroidTransitionActivity.TransitionType.Diagonal) {  
                overridePendingTransition(R.anim.diagonal_in, R.anim.diagonal_out);  
           }   
      }  
 }  

Чуть не забыл про AndroidManifest.xml файл. Туда нам необходимо прописать наше добавленное activity ( SecondActivity.java ), иначе ничего работать не будет.  Сделаем мы это вот так:

AndroidManifest.xml
 //...
  <application  
     android:icon="@drawable/ic_launcher"  
     android:label="@string/app_name" >  
     <activity  
       android:label="@string/app_name"  
       android:name=".AndroidTransitionActivity" >  
       <intent-filter >  
         <action android:name="android.intent.action.MAIN" />  
         <category android:name="android.intent.category.LAUNCHER" />  
       </intent-filter>  
     </activity>  
     <activity android:name="SecondActivity"></activity>  // Вот эту строку добавили
   </application> 
 //...

Вот теперь все. После всех добавлений наше приложение имеет вот такую структуру:


Вот такие результаты получились:

diagonal-анимация
zoom-анимация
slide-анимация


Ну все. Мы достигли поставленной задачи и немного разобрались с анимированными переходами  в Android. Теперь наши приложения будут выглядеть ещё красивее.
Надеюсь все, что здесь было показано, понятно.

8 комментариев:

  1. Этот комментарий был удален автором.

    ОтветитьУдалить
  2. Здрасьте, а как сделать что бы переходил с фрагмента на активити с анимацией, а то ругается на эту строчку overridePendingTransition, заранее спасибо

    ОтветитьУдалить
    Ответы
    1. Вот мое решение на ваш вопрос.

      Первый класс - содержащий фрагмент:

      /**
      * @author andrey_lunevich
      *
      */
      public class MainActivity extends FragmentActivity {

      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
      MainFragment list = MainFragment.newInsatance();
      getSupportFragmentManager().beginTransaction().add(android.R.id.content, list).commit();
      }
      }

      public static class MainFragment extends Fragment implements OnClickListener {

      public static MainFragment newInsatance() {
      return new MainFragment();
      }

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View v = inflater.inflate(R.layout.main_fragment, container, false);

      Button btn = (Button) v.findViewById(R.id.button1);
      btn.setOnClickListener(this);

      return v;
      }

      @Override
      public void onClick(View v) {
      getActivity().finish();
      Intent intent = new Intent(getActivity(), SecondActivity.class);
      startActivity(intent);
      switch (v.getId()) {
      case R.id.button1:
      getActivity().overridePendingTransition(R.anim.slide_left_in, R.anim.slide_left_out);
      break;
      }
      }
      }
      }

      Второе активити в которое переходим из фрагмента:

      /**
      * @author andrey_lunevich
      *
      */
      public class SecondActivity extends Activity {

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

      Надеюсь ответил на ваш вопрос :)

      Удалить
  3. Сделал в точности как написано. При нажатии кнопок анимации не происходит. Просто переключается активити. Что делать?

    ОтветитьУдалить
    Ответы
    1. Можете скинуть ваш шаблон ?

      Удалить
    2. Аналогичная ситуация, компилировал под Android 2.3.3. Анимации не происходит.

      Удалить
    3. Проблема решилась у меня на Samsung (android 2.3.6) просто изменением в настройках самого устройства:
      Settings -> Display -> Animation
      Настройки -> Дисплей -> Анимация
      Ставим галочку вся анимация :)

      Удалить
  4. Этот комментарий был удален автором.

    ОтветитьУдалить