Практика
Заметка: Для того чтобы комментарии в скаченном проекте были
читаемы (русский язык), необходимо поменять кодировку проекта на UTF-8 (Project –> Properties –> Resource –> Text file incoding).
Для анимации летающих ячеек необходимо изменить макет main.xml, в котором находиться наш ListView. Добавим в него ImageVIew, который будет
выступать в качестве летающей ячейки. Мы будем использовать данную идею по той
причине, что анимировать View
самого элемента, как мы это делали в предыдущей статье, у нас не получится.
Потому что каждая ячейка списка распологается друг под другом, и при
перемещении верхних ячеек вниз, их будут перекрывать нижнии ячейки.
Исходный код (main.xml)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white" >
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cacheColorHint="@android:color/transparent" />
<ImageView
android:id="@+id/flyingCell"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
</FrameLayout>
Добавим необходимые атрибуты в Activity.
// Сообщения для Handler'а public static final int MSG_ANIMATION_FLY = 3; // Хранит размеры экрана private DisplayMetrics dm = new DisplayMetrics(); // Летающая ячейка private ImageView flying_cell;
В методе onCreate() добавим инициализацию ImageView и DisplayMetrics.
flying_cell = (ImageView)findViewById(R.id.flyingCell); getWindowManager().getDefaultDisplay().getMetrics(dm);
Разработаем метод в нашем Activity, который будет выполнять перемещение выделенного элемента от его текущего положения к заданному.
/** * Запуск анимации летающей ячейки */ private void startFly(Bitmap cellBitmap, Point start, Point end, ToDoItem item) { flying_cell.setVisibility(View.VISIBLE); flying_cell.setImageBitmap(cellBitmap); TranslateAnimation translateAnimation = new TranslateAnimation(start.x, end.x, start.y, end.y); translateAnimation.setStartOffset(100); translateAnimation.setDuration(800); translateAnimation.setInterpolator(AnimationUtils.loadInterpolator(this, android.R.anim.accelerate_decelerate_interpolator)); /* Здесь используется AnimationSet, чтобы можно было добавить еще какую-нибудь анимацию (например, сначала увеличить ячейку, потом переместить и уменьшить до нормального размера) */ AnimationSet spriteAnimation = new AnimationSet(true); spriteAnimation.addAnimation(translateAnimation); spriteAnimation.setAnimationListener(new FlyAnimationListenter()); flying_cell.startAnimation(spriteAnimation); }
Нашей задачей также является отследить окончание анимации, после чего выполнить обновление списка.
/** * Listenter служит для обновления списка после того, как ячейка прилетела в нужную позицию */ public class FlyAnimationListenter implements Animation.AnimationListener { @Override public void onAnimationEnd(Animation arg0) { getHandler().sendEmptyMessage(MSG_CHANGE_ITEM); } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationStart(Animation animation) { } }
Так же добавим метод, который позволяет определить, запущена ли анимация или нет. Это необходимо для того, чтобы одновременно можно было выполнить только одну анимацию.
/** * Запущена ли анимация или нет */ public boolean isAnimationStarted() { return flying_cell.isShown(); }
В Handler добавляем дополнительный case. Идея летающих ячеек заключается в следующем алгоритме. При выборе ячейки мы получаем ее изображение (Bitmap). Далее расчитываем начальное положение ячейки, как верхняя координата списка + высота заголовка + общий размер всех ячеек, которые предшествуют выбранной ячейке. Затем надо отсортировать список и расчитать по той же формуле конечное положение. После откорректировать конечную точку с учетом размера экрана и выполнить анимацию.
... case MSG_CHANGE_ITEM: // Завершение анимации с летающими ячейками flying_cell.setVisibility(View.GONE); adapter.notifyDataSetChanged(); setCountPurchaseProduct(); break; ... case MSG_ANIMATION_FLY: // Старт анимации летающих ячеек Bitmap cellBitmap = (Bitmap)msg.obj; ToDoItem item = list.get(msg.arg1); item.setCheck(!item.isCheck()); Point startPoint, endPoint; /* Нам необходимы следующие значения для поиска позиции: height = Высота одной ячейка header_height = Высота Header'a листа (так же это высота первой ячейки в листе) listTop = Верхняя точка нашего списка - размер проскроллированной области */ int height = listview.getChildAt(1).getHeight(); int header_height = listview.getChildAt(0).getBottom(); int listTop = listview.getTop() - height * listview.getFirstVisiblePosition(); /* Поиск начальной и конечной точки происходит по следующему алгоритму: 1. Находим начальную точку: верхняя точка листа + высота первой ячейки + общая высота всех ячеек, которые предшествуют выбранной ячейки 2. Сортируем список с учетом новой позиции выбранной ячейки 3. Находим конечную точку: верхняя точка листа + высота первой ячейки + общая высота всех ячеек, которые предшествуют выбранной ячейки */ startPoint = new Point(0, listTop + header_height + height * getPositionInList(item.getIndex())); Utils.sorting(list, 0); saveList(); endPoint = new Point(0, listTop + header_height + height * getPositionInList(item.getIndex())); // Откорректируем конечную точку с учетом размеров экрана if (endPoint.y > dm.heightPixels) endPoint.y = dm.heightPixels; else if (endPoint.y < -1*height) endPoint.y = -1*height; // Если ячейка меняет позицию, то запускаем анимацию if (endPoint.y != startPoint.y) startFly(cellBitmap, startPoint, endPoint, item); else handler.sendEmptyMessage(MSG_CHANGE_ITEM); break;
Теперь необходимо изменить все методы, которые используются для выбора элемента в соответствии с новыми изменениями:
- метод OnItemClickListener() для Listview:
listview.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { // Если произошло нажатие по Header или Footer или анимация уже запущена, то ничего не делаем if (position == 0 || position == list.size() + 1 || isAnimationStarted()) return; Message msg = new Message(); msg.arg1 = position - 1; // Если был обнаружен свайп, то удаляем айтем if (swipeDetector.swipeDetected()){ if (swipeDetector.getAction() == SwipeDetector.Action.LR || swipeDetector.getAction() == SwipeDetector.Action.RL) { msg.what = MSG_ANIMATION_REMOVE; msg.arg2 = swipeDetector.getAction() == SwipeDetector.Action.LR ? 1 : 0; msg.obj = view; } } // Иначе выбираем айтем else { view.setDrawingCacheEnabled(true); Bitmap cellBitmap = view.getDrawingCache().copy(Config.ARGB_8888, false); view.setVisibility(View.INVISIBLE); msg.obj = cellBitmap; msg.what = MSG_ANIMATION_FLY; } handler.sendMessage(msg); } });
- метод OnClickListener () для CheckBox в классе CustomListAdapter:
final View tmp = v; listitem_check.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (((MainActivity)context).isAnimationStarted()) return; tmp.setDrawingCacheEnabled(true); Bitmap cellBitmap = tmp.getDrawingCache().copy(Config.ARGB_8888, false); tmp.setVisibility(View.INVISIBLE); Message msg = new Message(); msg.obj = cellBitmap; msg.arg1 = position; msg.what = MainActivity.MSG_ANIMATION_FLY; ((MainActivity)context).getHandler().sendMessage(msg); } });
Комментариев нет:
Отправить комментарий