“穷达自有常,得失又何求。”——(魏)阮籍《咏怀》其二十八。一晃将近一个月的时间没有写博客了,安逸的时光总是那么快。春天来了,大地回春,万物复苏,一年之计在于春。算了,算了,不感慨了,总之多写几篇博客肯定没坏处。最近做项目用到了ListView,然后在GitHub上看到了一个很好的开源项目ListViewAnimations,给大家分享一下!
项目介绍
ListViewAnimations是一个开源Android库,开发人员通过它可以很轻松地创建带动画的ListView。ListViewAnimations提供的功能主要包括:
① ListViews,GridViews和其他AbsListViews的外观效果:
(1)数据展现的动画包括:Alpha(透明渐入),SwingRightIn(右侧进入),SwingLeftIn(左侧进入),SwingBottomIn(底部进入)和ScaleIn(由小变大)
(2)添加其他动画
(3)支持StickyListHeaders
② 通过滑动删除子项数据,并且支持撤销
③ 通过拖动对数据进行排序
④ 支持添加数据,以显示更多的内容,并有相应动画
空口无凭,先来一张效果图:
准备工作
该库包含以下三个单独的模块:
① lib-core:库的核心,包含外观动画
② lib-manipulation:包含项目操作选项,例如Swipe-to-Dismiss和Drag-and-Drop
③ lib-core-slh:是lib-core的扩展,支持StickyListHeaders
值得注意的是,当使用lib-manipulation或时lib-core-slh,lib-core也包括在内。
方法一:
将以下内容添加到您的build.gradle:
repositories {
mavenCentral()
}
dependencies {
compile 'com.nhaarman.listviewanimations:lib-core:3.1.0@aar'
compile 'com.nhaarman.listviewanimations:lib-manipulation:3.1.0@aar'
compile 'com.nhaarman.listviewanimations:lib-core-slh:3.1.0@aar'
}
方法二:
1、下载所需的jar包,lib-core、lib-manipulation和lib-core-slh。
2、下载最新的NineOldAndroids .jar文件
3、将.jar文件添加到项目的libs文件夹中,或将它们作为外部jar添加到项目的构建路径中
方法三:
将以下内容添加到您的pom.xml:
<dependency>
<groupId>com.nhaarman.listviewanimations</groupId>
<artifactId>lib-core</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.nhaarman.listviewanimations</groupId>
<artifactId>lib-manipulation</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.nhaarman.listviewanimations</groupId>
<artifactId>lib-core-slh</artifactId>
<version>3.1.0</version>
</dependency>
入门环节
如果您已经按照上述的方法完成了相关操作,那么我们接下来就开始向ListView添加动画。
外观动画
com.nhaarman.listviewanimations.appearance包中的类通过为ListView添加更多花哨性的方法为我们提供了在第一次显示数据时的一些动画效果。这里指的不是将数据捕捉到视图中,而是将数据呈现给用户。效果图来一张:
要实现这种效果,需要将之前的Adapter包装在AlphaInAnimationAdapter中:
MyAdapter myAdapter = new MyAdapter();
AlphaInAnimationAdapter animationAdapter = new AlphaInAnimationAdapter(myAdapter);
animationAdapter.setAbsListView(mListView);
mListView.setAdapter(animationAdapter);
您可以创建自己的AnimationAdapter实现,也可以使用其中一个预定义的实现:AlphaInAnimationAdapter、ScaleInAnimationAdapter、SwingBottomInAnimationAdapter、SwingLeftInAnimationAdapter和SwingRightInAnimationAdapter。而MyAdapter需要是BaseAdapter,文末给出了一个简单的MyAdapter例子,仅供参考。
DynamicListView
DynamicListView是一个便利类,它提供拖动,滑动移除和插入动画等功能。它旨在以最佳方式实现这些功能。上图:
首先,要使用DynamicListView,需要在xml布局中添加DynamicListView控件:
<com.nhaarman.listviewanimations.itemmanipulation.DynamicListView
android:id = “@ + id / dynamiclistview”
android:layout_width = “match_parent”
android:layout_height = “match_parent” />
拖动
要启用拖放功能,只需对您的DynamicListView调用enableDragAndDrop()方法,来指定项目何时可拖动,然后指定可以通过触摸来启动拖动的控件,您可以使用TouchViewDraggableManager:
mDynamicListView.enableDragAndDrop();
mDynamicList.setDraggableManager(new TouchViewDraggableManager(LayoutInflater.from(LayerManagerActivity.this).inflate(R.layout.item_layer_info,null).findViewById(R.id.item_layer_gripview).getId()));
另外,也可以通过调用startDragging(int)方法来进行拖动,例如设置OnItemLongClickListener:
mDynamicListView.enableDragAndDrop();
mDynamicListView.setOnItemLongClickListener(
new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(final AdapterView<?> parent, final View view,
final int position, final long id) {
mDynamicListView.startDragging(position);
return true;
}
}
);
请注意,拖动功能仅适用于运行ICS(API 14)及更高版本的设备。
滑动移除
为了实现滑动移除,需要将DynamicListView调用enableSwipeToDismiss(OnDismissCallback)方法。在OnDismissCallback中给出移除的数据项,并负责从数据集中移除该数据项:
mDynamicListView.enableSwipeToDismiss(
new OnDismissCallback() {
@Override
public void onDismiss(@NonNull final ViewGroup listView, @NonNull final int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
mAdapter.remove(position);
}
}
}
);
带有撤销的滑动移除
要实现带有撤消的滑动移除功能,需要将mAdapter包装在SimpleSwipeUndoAdapter或者TimedUndoAdapter中,而后者当它进入撤消状态时将在一段时间内自动移除数据项。
MyAdapter myAdapter = new MyAdapter();
SimpleSwipeUndoAdapter swipeUndoAdapter = new SimpleSwipeUndoAdapter(myAdapter, MyActivity.this,
new OnDismissCallback() {
@Override
public void onDismiss(@NonNull final ViewGroup listView, @NonNull final int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
mAdapter.remove(position);
}
}
}
);
swipeUndoAdapter.setAbsListView(mDynamicListView);
mDynamicListView.setAdapter(swipeUndoAdapter);
mDynamicListView.enableSimpleSwipeUndo();
数据项添加
DynamicListView还可以在数据集中加入项目,并且带有相关动画。要使用此功能,只需让mAdapter实现Insertable,并调用insert方法:
MyInsertableAdapter myAdapter = new MyInsertableAdapter(); // MyInsertableAdapter implements Insertable
mDynamicListView.setAdapter(myAdapter);
mDynamicListView.insert(0, myItem); // myItem is of the type the adapter represents.
StickyListHeaders
ListViewAnimations还支持StickyListHeaderListViews,而且带有外观动画,需要通过将AnimationAdapter包装在StickyListHeadersAdapterDecorator中:
StickyListHeadersListView listView = (...);
AlphaInAnimationAdapter animationAdapter = new AlphaInAnimationAdapter(adapter);
StickyListHeadersAdapterDecorator stickyListHeadersAdapterDecorator = new StickyListHeadersAdapterDecorator(animationAdapter);
stickyListHeadersAdapterDecorator.setStickyListHeadersListView(listView);
listView.setAdapter(stickyListHeadersAdapterDecorator);
MyAdapter
最后是一个基本的MyAdapter类,可以拿来照葫芦画瓢。
/*
* Copyright 2014 Niek Haarman
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ac.aircas.smartmap.collection.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.ac.aircas.smartmap.R;
import com.ac.aircas.smartmap.collection.bean.DrawingBean;
import com.nhaarman.listviewanimations.ArrayAdapter;
import com.nhaarman.listviewanimations.itemmanipulation.dragdrop.GripView;
import com.nhaarman.listviewanimations.itemmanipulation.swipedismiss.undo.UndoAdapter;
import java.util.ArrayList;
import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
public class MyListAdapter extends ArrayAdapter<String> implements UndoAdapter, StickyListHeadersAdapter {
private final Context mContext;
private ArrayList<DrawingBean> drawingBeans;
public MyListAdapter(final Context context,ArrayList<DrawingBean> drawingBeans) {
this.mContext = context;
this.drawingBeans = drawingBeans;
for (int i = 0; i < drawingBeans.size(); i++) {
add(String.valueOf(i));
}
}
@Override
public long getItemId(final int position) {
return getItem(position).hashCode();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewHolder viewHolder;
//如果view未被实例化过,缓存池中没有对应的缓存
if (convertView == null) {
viewHolder = new ViewHolder();
// 由于我们只需要将XML转化为View,并不涉及到具体的布局,所以第二个参数通常设置为null
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_layer_info, parent, false);
//对viewHolder的属性进行赋值
viewHolder.name = (TextView) convertView.findViewById(R.id.item_layer_name);
viewHolder.type = (TextView) convertView.findViewById(R.id.item_layer_type);
viewHolder.gripView = (GripView) convertView.findViewById(R.id.item_layer_gripview);
//通过setTag将convertView与viewHolder关联
convertView.setTag(viewHolder);
} else {//如果缓存池中有对应的view缓存,则直接通过getTag取出viewHolder
viewHolder = (ViewHolder) convertView.getTag();
}
// 取出bean对象
DrawingBean bean = drawingBeans.get(Integer.parseInt((getItem(position))));
// 设置控件的数据
viewHolder.name.setText(bean.getName());
viewHolder.type.setText(bean.getType());
return convertView;
}
@NonNull
@Override
public View getUndoView(final int position, final View convertView, @NonNull final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.undo_row, parent, false);
}
return view;
}
@NonNull
@Override
public View getUndoClickView(@NonNull final View view) {
return view.findViewById(R.id.undo_row_undobutton);
}
@Override
public View getHeaderView(final int position, final View convertView, final ViewGroup parent) {
TextView view = (TextView) convertView;
if (view == null) {
view = (TextView) LayoutInflater.from(mContext).inflate(R.layout.list_header, parent, false);
}
view.setText(mContext.getString(R.string.header, getHeaderId(position)));
return view;
}
@Override
public long getHeaderId(final int position) {
return position / 10;
}
// ViewHolder用于缓存控件,三个属性分别对应item布局文件的三个控件
class ViewHolder {
public TextView name;
public TextView type;
public GripView gripView;
}
}
就这么多吧,祝编程顺利!^(* ̄(oo) ̄)^
参考
原文地址:http://nhaarman.github.io/ListViewAnimations/#getting-started