Практика
Заметка: Для того чтобы комментарии в скаченном проекте были
читаемы (русский язык), необходимо поменять кодировку проекта на 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);
}
});
Комментариев нет:
Отправить комментарий