суббота, 16 августа 2014 г.

Создание по кадровой анимации для Андроид
с подробным объяснением действий и кода 

Frame animation in Android

(автор Валерий Старощук)
Преамбула

Статья писалась для себя, так как при изучении Андроид столкнулся с некоторым высокомерием разработчиков, которые «стесняются» людям пояснять якобы простые вопросы, но при этом открывают зачем-то форумы, где вас в лучшем случае пошлют в Google или на худой конец на http://developer.android.com/.
В статье могут быть ошибки с точки зрения пояснения работы приложения и в терминах. Писал так, как понятно мне. Могу только заверить вас, что приложение работает.

Простым смертным разработчикам посвящается...

Анимация создавалась в программе-оболочке Eclipse. Как её установить и настроить вы найдете в Интернете. Учитывая, что программа постоянно обновляется, вид скриншотов может отличаться от того, что увидите вы на тот день, когда будете читать эту статью.
Итак начнем...

1. Создайте свой проект.
- Запустите программу Eclipse. 
- Открываем закладку File -> New -> Android Application Project.
- Заполним форму проекта.
    На моем скриншоте рядом с красным кружком предупреждение, что проект с таким именем уже существует (он действительно у меня уже есть), у вас такой надписи не должно быть! Если у вас есть такой проект, тогда меняйте название, но не забудьте его изменить в последующих файлах, где размещен код.
- Заполняем поле
Application Name: My Animation.
Остальные поля заполняются автоматически программой.
В поле темы приложения (Theme:) выберите None.
Если всё правильно, у вас активируется кнопка Next, жмем на неё.
Появляется новое окно

- Убираем галочку напротив надписи Create custom launcher icon (Создание своей иконки запуска). 
Жмем Next.
Появляется окно, предлагающее создать Activity.

- Соглашаемся и нажимаем Next.
Появляется следующее окно, предлагающее создать файл Активити.

Напротив LayoutName пишем main. Нажимаем кнопку Finish.
Должно появиться примерно такое окно.
У вас будет автоматически открыт файл main.xml из папки  res/layout/ в графическом виде. Активити будет состоять из фразы Hello world! Вверху иконка андроида по умолчанию, которую мы не захотели менять, убрав галочку напротив Create custom launcher icon и название приложения. У меня, как вы видите My Animations, а у вас должно быть My Animation, без буквы s в конце. Итак, заготовка готова. Теперь начинаем её менять.

2. Прежде, чем менять, несколько слов о кадровой анимации.
Это классический вид анимации, когда движущееся изображение создается при быстром просматривании кадров. Человек перестает замечать отдельные кадры при частоте их прокрутки более 24 - 25 кадров в секунду. При меньшем количестве кадров изображение кажется «дерганным» или дрожащим. Также важно, чтобы объект, который движется, изменял свое положение или форму на незначительную величину. Учитывая, что скорость обработки информации, а также оперативная память мобильных телефонов и планшетов уступает стационарным компьютерам, разработчику покадровой анимации нужно это учитывать. Нужно задать себе вопрос, а успеет ли устройство загрузить в оперативную память картинку, которая занимает, например, 100 МВ за время 0,04 с (25 кадр/с), чтобы ее воспроизвести на экране?

2.1 Загружаем в папку /res/drawable кадры анимации в формате png или jpg. В моем примере это 20 картинок лошади с наездником (horse01.png – horse20.png) примерно по 107 кВ каждая. 
Изображения картинок и все файлы приложения с кодами можно скачать здесь

2.2 В эту же папку /res/drawable размещаем файл horse.xml.
XML файл состоит из элемента <animation-list> в качестве корневого узла и серии дочерних <item> узлов, в каждом из которых прописан ресурс для кадра (drawable) и его длительность в миллисекундах. У нас установлена длительность 250 мс (4 кадра/с) и вы увидите, как дергается изображение. Потом попробуйте уменьшить время проигрывания одного кадра до 50 мс, и увидите, что лошадь двигается плавно. Нужно также понимать, что увеличивая скорости загрузок, вы садите батарейку вашего гаджета. Иногда люди отказываются от приложения, увидев, что телефон разрядился за 1 день, хотя раньше работал три дня. Но сегодня не об этом.

Файл horse.xml

<?xml version="1.0" encoding="utf-8"?>

<animation-list 
xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/horse01" android:duration="250"/>
    <item android:drawable="@drawable/horse02" android:duration="250"/>
    <item android:drawable="@drawable/horse03" android:duration="250"/>
    <item android:drawable="@drawable/horse04" android:duration="250"/>
    <item android:drawable="@drawable/horse05" android:duration="250"/>
    <item android:drawable="@drawable/horse06" android:duration="250"/>
    <item android:drawable="@drawable/horse07" android:duration="250"/>
    <item android:drawable="@drawable/horse08" android:duration="250"/>
    <item android:drawable="@drawable/horse09" android:duration="250"/>
    <item android:drawable="@drawable/horse10" android:duration="250"/>
    <item android:drawable="@drawable/horse11" android:duration="250"/>
    <item android:drawable="@drawable/horse12" android:duration="250"/>
    <item android:drawable="@drawable/horse13" android:duration="250"/>
    <item android:drawable="@drawable/horse14" android:duration="250"/>
    <item android:drawable="@drawable/horse15" android:duration="250"/>
    <item android:drawable="@drawable/horse16" android:duration="250"/>
    <item android:drawable="@drawable/horse17" android:duration="250"/>
    <item android:drawable="@drawable/horse18" android:duration="250"/>
    <item android:drawable="@drawable/horse19" android:duration="250"/>
    <item android:drawable="@drawable/horse20" android:duration="250"/>
    
</animation-list>    

Если элемент android:oneshot="false", то кадры будут проигрываться непрерывно, пока мы их сами не остановим кнопкой Стоп, если "true", то проигрывание будет с 1 по 20 кадр и приложение остановится.

2.3 Меняем содержимое файла main.xml из папки /res/layout. Теперь оно должно быть таким.

Файл 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" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn_start"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10px"
            android:layout_weight="1"
            android:text="Пуск" />

        <Button
            android:id="@+id/btn_stop"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10px"
            android:layout_weight="1"
            android:text="Стоп" />
    </LinearLayout>

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Иногда этот файл называют файлом разметки. Здесь мы задаём то, что увидит пользователь первый раз запустив Активити (приложение).

    Первой строкой задаем вид кодировки. При настройке Eclipse это уже делалось, но на всякий случай её объявляют вновь и вновь. 
<?xml version="1.0" encoding="utf-8"?>

    Во второй строке
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
Мы объявляем пространство имен, чтобы не прописывать все время полный путь к каждому файлу. В интернете доменного имени http://schemas.android.com/apk/res/android не существует (проверял).

Объявление пространства имен имеет следующий синтаксис
xmlns:prefix="URI"

    Uniform Resource Identifier (URI) представляет собой строку символов, которые идентифицирует ресурс в Интернет. Наиболее распространенным URI является унифицированный указатель информационного ресурса (URL), который идентифицирует адрес домена Интернет. Другой, не так распространенный тип URI является Universal Resource Name (URN).

    Элемент LinearLayout задает вид разметки нашего Активити.
Разметка LinearLayout выравнивает все дочерние объекты в одном направлении — вертикально или горизонтально. Направление задается при помощи атрибута ориентации android:orientation, например:
android:orientation="horizontal"
android:orientation="vertical"

Все дочерние элементы помещаются в стек один за другим, так что вертикальный список представлений будет иметь только один дочерний элемент в строке независимо от того, насколько широким он является. Горизонтальное расположение списка будет размещать элементы в одну строку с высотой, равной высоте самого высокого дочернего элемента списка.
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
Эти три строки означают, что наш слой Активити заполняет все пространство по ширине и высоте экрана, ориентация которого вертикальная.

Потом мы создаем еще один слой методом LinearLayout для двух кнопок.
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
По ширине этот слой на весь экран, а по высоте будет занимать высоту кнопки. Ориентация кнопок – горизонтальная.

Создаем сами кнопки.

Разберем, что означают эти строки

<Button
            android:id="@+id/btn_start"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10px"
            android:layout_weight="1"
            android:text="Пуск" />

Строкой android:id="@+id/btn_start" мы даем указание программе создать идентификатор в файле идентификаторов R.java (он находится в папке gen).

android:layout_width="fill_parent
 android:layout_height="wrap_content"
Здесь определяем ширину и высоту кнопки.

 android:layout_marginTop="10px"
Данной строкой мы организуем отступ от верхнего края заголовка. Обратите внимание на фото.

Следующая строка задает вес слоя. 
android:layout_weight="1"

Если бы кнопка была одна, она бы стала по ширине на весь экран. Но мы создаем две кнопки, размещенные горизонтально с одинаковым весом, поэтому экран по ширине делится автоматически пополам для двух кнопок.

            android:text="Пуск" />
Задаем имя кнопки. 
Желтые треугольники, говорят нам, что таких строк нет у ресурса данного приложения. Андроид следит, чтобы в файл вставлялись строки из ресурсов. Это удобно, так как если вы поменяете название кнопки, то вам достаточно изменить его один раз в ресурсах, а не в каждом файде, где прописана эта кнопка. В принципе, это замечание и его можно пропустить, приложение все равно будет работать. Но меня эти замечания раздражают. Чтобы они исчезли нужно прописать в файле strings.xml папка ресурсов values две строчки
<string name="run">Пуск</string>
<string name="stop">Стоп</string>
А в файле main.xml
Вместо строки
android:text="Пуск"
при создании кнопки Пуск, записать
android:text="@string/run"
Аналогично проделать для кнопки Стоп.
Вместо
android:text="Стоп"
записать
android:text="@string/stop"
Предупреждения исчезнут.

3. Осталось разобрать последний файл, который и проделает всю работу по кадровой анимации.

Файл MainActivity.java

/*Сначала мы указываем виртуальной машине Андроид пакет для компиляции, где хранятся все файлы нашего проекта*/
package com.example.myanimation;

/*Загружаем нужные библиотеки*/
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

Кстати, если у вас не хватает какой-либо библиотеки, Андроид это узнает и выдаст вам ошибку с просьбой загрузить. Сочетание кнопок ctrl+shift+о позволит сделать вам это автоматически.

/* Объявляем класс MainActivity, который наследует свойства класса Activity*/
public class MainActivity extends Activity {

/*Объявляем метод*/
AnimationDrawable mAnim;
    /* Данный метод onCreate вызывается, когда Активити запускается первый раз */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        /* метод сохраняет положение настроек в тот момент, когда Активити прекращает работу*/
        super.onCreate(savedInstanceState);
       /* вызываем по файлу идентификаторов (R.java) содержимое main.xml*/
        setContentView(R.layout.main);
        
/*Запускаем метод ImageView для image, который нашли в R.java*/
        ImageView image = (ImageView)findViewById(R.id.image);
/* Находим по идентификатору в папке drawable файл horse. xml и прикрепляем его, как ресурс к области  image */
        image.setBackgroundResource(R.drawable.horse);
    /*В переменную mAnim записываем картинку из ресурса*/    
        mAnim = (AnimationDrawable)image.getBackground();
        
/*Находим кнопу Старт и применяем к ней метод setOnClickListener, т.е проверяем её нажатие*/
        final Button btnStart = (Button) findViewById(R.id.btn_start);
        btnStart.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
/*Если кнопка нажата запускаем анимацию*/
                mAnim.start();
            }
        });
     /*Если нажата кнопка Стоп, останавливаем анимацию*/       
        final Button btnStop = (Button) findViewById(R.id.btn_stop);
        btnStop.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                mAnim.stop();
            }
        });      
    }
}

Всё сохраняем.

4. В Package Exsplorer правой кнопкой выделяем папку с нашим проектом My Animation. Выпадает меню, ищем Run As -> Android Applicatoin

Нажимаем Enter.
Ждем, в зависимости от быстродействия компьютера может пройти от 3 до 30 с.
Появится виртуальная модель нашего телефона.
Наслаждаемся работой! 
Смотри видео



PS
Здесь моя статья о покадровой анимации на Андроид Студио.
http://androidalwaysdream.blogspot.com/search/label/Frame%20Animation







Комментариев нет:

Отправить комментарий