转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/18311877),请尊重他人的辛勤劳动成果,谢谢!
今天还是给大家带来自定义控件的编写,自定义一个ListView的左右滑动删除Item的效果,这个效果之前已经实现过了,有兴趣的可以看下Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果,之前使用的是滑动类Scroller来实现的,但是看了下通知栏的左右滑动删除效果,确实很棒,当我们滑动Item超过一半的时候,item的透明度就变成了0,我们就知道抬起手指的时候item就被删除了,当item的透明度不为0的时候,我们抬起手指Item会回到起始位置,这样我们就知道拖动到什么位置item会删除,什么位置Item不删除,用户体验更好了,还有一个效果,就是我们滑动删除了item的时候,ListView的其他item会出现向上或者向下滚动的效果,感觉效果很棒,所以在GitHub上面搜索了下,发现很多开源库都有这个效果,比如ListViewAnimations, android-swipelistview等等,我看了下实现原理,使用的是Jake Wharton的动画开源库NineOldAndroids,这个库究竟是干嘛的呢?在API3.0(Honeycomb), SDK新增了一个android.animation包,里面的类是实现动画效果相关的类,通过Honeycomb API,能够实现非常复杂的动画效果,但是如果开发者想在3.0以下使用这一套API, 则需要使用开源框架Nine Old Androids,在这个库中会根据我们运行的机器判断其SDK版本,如果是API3.0以上则使用Android自带的动画类,否则就使用Nine Old Androids库中,这是一个兼容库,接下来我们就来看看这个效果的具体实现吧
实现该效果的主要思路
- 先根据手指触摸的点来获取点击的是ListView的哪一个Item
- 当手指在屏幕上面滑动的时候,我们要使得Item跟随手指的滑动而滑动
- 当我们抬起手指的时候,我们根据滑动的距离或者手指在屏幕上面的速度来判断Item是滑出屏幕还是滑动至其实位置
- Item滑出屏幕时,使ListView的其他item产生向上挤压或者向下挤压的效果
大致的思路这是这四步,其中的一些细节接下来我会一一为大家解答的,接下来我们就用代码来实现这种效果吧
首先我们新建一个工程,叫Swipedismisslistview,我们需要将Nine Old Androids这个库引入到工程,大家可以去https://github.com/JakeWharton/NineOldAndroids下载,可以使用Jar包,也可以使用工程库的形式引入到我们自己的工程,我们还需要自定义一个ListView,我们先看代码然后给大家讲解下具体的功能实现
- package com.example.swipedismisslistview;
- import static com.nineoldandroids.view.ViewHelper.setAlpha;
- import static com.nineoldandroids.view.ViewHelper.setTranslationX;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.VelocityTracker;
- import android.view.View;
- import android.view.ViewConfiguration;
- import android.view.ViewGroup;
- import android.widget.AdapterView;
- import android.widget.ListView;
- import com.nineoldandroids.animation.Animator;
- import com.nineoldandroids.animation.AnimatorListenerAdapter;
- import com.nineoldandroids.animation.ValueAnimator;
- import com.nineoldandroids.view.ViewHelper;
- import com.nineoldandroids.view.ViewPropertyAnimator;
- /**
- * @blog http://blog.csdn.net/xiaanming
- *
- * @author xiaanming
- *
- */
- public class SwipeDismissListView extends ListView {
- /**
- * 认为是用户滑动的最小距离
- */
- private int mSlop;
- /**
- * 滑动的最小速度
- */
- private int mMinFlingVelocity;
- /**
- * 滑动的最大速度
- */
- private int mMaxFlingVelocity;
- /**
- * 执行动画的时间
- */
- protected long mAnimationTime = 150;
- /**
- * 用来标记用户是否正在滑动中
- */
- private boolean mSwiping;
- /**
- * 滑动速度检测类
- */
- private VelocityTracker mVelocityTracker;
- /**
- * 手指按下的position
- */
- private int mDownPosition;
- /**
- * 按下的item对应的View
- */
- private View mDownView;
- private float mDownX;
- private float mDownY;
- /**
- * item的宽度
- */
- private int mViewWidth;
- /**
- * 当ListView的Item滑出界面回调的接口
- */
- private OnDismissCallback onDismissCallback;
- /**
- * 设置动画时间
- *
- * @param mAnimationTime
- */
- public void setmAnimationTime(long mAnimationTime) {
- this.mAnimationTime = mAnimationTime;
- }
- /**
- * 设置删除回调接口
- *
- * @param onDismissCallback
- */
- public void setOnDismissCallback(OnDismissCallback onDismissCallback) {
- this.onDismissCallback = onDismissCallback;
- }
- public SwipeDismissListView(Context context) {
- this(context, null);
- }
- public SwipeDismissListView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public SwipeDismissListView(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- ViewConfiguration vc = ViewConfiguration.get(context);
- mSlop = vc.getScaledTouchSlop();
- mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 8; //获取滑动的最小速度
- mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); //获取滑动的最大速度
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- handleActionDown(ev);
- break;
- case MotionEvent.ACTION_MOVE:
- return handleActionMove(ev);
- case MotionEvent.ACTION_UP:
- handleActionUp(ev);
- break;
- }
- return super.onTouchEvent(ev);
- }
- /**
- * 按下事件处理
- *
- * @param ev
- * @return
- */
- private void handleActionDown(MotionEvent ev) {
- mDownX = ev.getX();
- mDownY = ev.getY();
- mDownPosition = pointToPosition((int) mDownX, (int) mDownY);
- if (mDownPosition == AdapterView.INVALID_POSITION) {
- return;
- }
- mDownView = getChildAt(mDownPosition - getFirstVisiblePosition());
- if (mDownView != null) {
- mViewWidth = mDownView.getWidth();
- }
- //加入速度检测
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(ev);
- }
- /**
- * 处理手指滑动的方法
- *
- * @param ev
- * @return
- */
- private boolean handleActionMove(MotionEvent ev) {
- if (mVelocityTracker == null || mDownView == null) {
- return super.onTouchEvent(ev);
- }
- // 获取X方向滑动的距离
- float deltaX = ev.getX() - mDownX;
- float deltaY = ev.getY() - mDownY;
- // X方向滑动的距离大于mSlop并且Y方向滑动的距离小于mSlop,表示可以滑动
- if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < mSlop) {
- mSwiping = true;
- //当手指滑动item,取消item的点击事件,不然我们滑动Item也伴随着item点击事件的发生
- MotionEvent cancelEvent = MotionEvent.obtain(ev);
- cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
- (ev.getActionIndex()<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));
- onTouchEvent(cancelEvent);
- }
- if (mSwiping) {
- // 跟谁手指移动item
- ViewHelper.setTranslationX(mDownView, deltaX);
- // 透明度渐变
- ViewHelper.setAlpha(mDownView, Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX)/ mViewWidth)));
- // 手指滑动的时候,返回true,表示SwipeDismissListView自己处理onTouchEvent,其他的就交给父类来处理
- return true;
- }
- return super.onTouchEvent(ev);
- }
- /**
- * 手指抬起的事件处理
- * @param ev
- */
- private void handleActionUp(MotionEvent ev) {
- if (mVelocityTracker == null || mDownView == null|| !mSwiping) {
- return;
- }
- float deltaX = ev.getX() - mDownX;
- //通过滑动的距离计算出X,Y方向的速度
- mVelocityTracker.computeCurrentVelocity(1000);
- float velocityX = Math.abs(mVelocityTracker.getXVelocity());
- float velocityY = Math.abs(mVelocityTracker.getYVelocity());
- boolean dismiss = false; //item是否要滑出屏幕
- boolean dismissRight = false;//是否往右边删除
- //当拖动item的距离大于item的一半,item滑出屏幕
- if (Math.abs(deltaX) > mViewWidth / 2) {
- dismiss = true;
- dismissRight = deltaX > 0;
- //手指在屏幕滑动的速度在某个范围内,也使得item滑出屏幕
- } else if (mMinFlingVelocity <= velocityX
- && velocityX <= mMaxFlingVelocity && velocityY < velocityX) {
- dismiss = true;
- dismissRight = mVelocityTracker.getXVelocity() > 0;
- }
- if (dismiss) {
- ViewPropertyAnimator.animate(mDownView)
- .translationX(dismissRight ? mViewWidth : -mViewWidth)//X轴方向的移动距离
- .alpha(0)
- .setDuration(mAnimationTime)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- //Item滑出界面之后执行删除
- performDismiss(mDownView, mDownPosition);
- }
- });
- } else {
- //将item滑动至开始位置
- ViewPropertyAnimator.animate(mDownView)
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime).setListener(null);
- }
- //移除速度检测
- if(mVelocityTracker != null){
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- mSwiping = false;
- }
- /**
- * 在此方法中执行item删除之后,其他的item向上或者向下滚动的动画,并且将position回调到方法onDismiss()中
- * @param dismissView
- * @param dismissPosition
- */
- private void performDismiss(final View dismissView, final int dismissPosition) {
- final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();//获取item的布局参数
- final int originalHeight = dismissView.getHeight();//item的高度
- ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 0).setDuration(mAnimationTime);
- animator.start();
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (onDismissCallback != null) {
- onDismissCallback.onDismiss(dismissPosition);
- }
- //这段代码很重要,因为我们并没有将item从ListView中移除,而是将item的高度设置为0
- //所以我们在动画执行完毕之后将item设置回来
- ViewHelper.setAlpha(dismissView, 1f);
- ViewHelper.setTranslationX(dismissView, 0);
- ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
- lp.height = originalHeight;
- dismissView.setLayoutParams(lp);
- }
- });
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- //这段代码的效果是ListView删除某item之后,其他的item向上滑动的效果
- lp.height = (Integer) valueAnimator.getAnimatedValue();
- dismissView.setLayoutParams(lp);
- }
- });
- }
- /**
- * 删除的回调接口
- *
- * @author xiaanming
- *
- */
- public interface OnDismissCallback {
- public void onDismiss(int dismissPosition);
- }
- }
看过Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果你会发现,这个自定义的SwipeDismissListView只重写了onTouchEvent()方法,其实我们重写这一个方法就能实现我们需要的效果
1. 我们先看手指按下屏幕的处理方法handleActionDown();该方法里面根据我们手指按下的点根据pointToPosition()方法来获取我们点击的position,然后利用getChildAt()来获取我们按下的item的View对象,并且加入手指在屏幕滑动的速度检查,这一步相对来说还是比较简单
2. 接下来就是手指在屏幕上面滑动的处理方法handleActionMove(),这个方法就稍微的复杂些,我们需要根据手指在X轴的滑动距离和Y轴的滑动距离来判断是ListView item的水平滑动还是ListView的上下滑动,当满足Math.abs(deltaX) > mSlop && Math.abs(deltaY) < mSlop这个条件时候,我们用一个布尔值mSwiping来标记Item现在处于水平滑动的状态,这时候我们需要处理Item跟随手指的滑动而滑动的逻辑,我们使用ViewHelper来处理Item的滑动逻辑,这个类会根据机器的SDK版本来判断使用Android系统的API还是NineOldandroids中自己实现的API使得View滑动的效果,NineOldandroids中主要使用Camera(可以实现各种复杂动画效果的类),我们直接使用ViewHelper的setTranslationX()和setAlpha()就实现了item滑动和透明度渐变的效果,为了使得我们在滑动item的时候,ListView不上下滚动,我们必须返回true来屏蔽ListView的上下滚动,这里需要我们要非常熟悉Android的事件分发机制,这里我就不说明了,大家不了解的去网上找找相关的文章看看
还有一个问题,就是当我们滑动ListView的item的时候,会伴随着item的点击事件,这不是我们想要的效果,所以当Item滑动的时候我们需要取消ListView Item的点击事件
3. 在看手指抬起的时候的处理方法handleActionUp(),这里面需要根据手指的滑动速度或者Item移动的距离来判断Item是滑出屏幕还是滑动至起始位置,并且要判断item向左还是向右滑出屏幕等等逻辑,具体的逻辑可以看代码,相信大家都看得懂.
我这里要说说ViewPropertyAnimator类,这个类能更好的实现一个View同时进行多个动画的功能,当然我们也可以使用ObjectAnimator利用AnimatorSet来实现一个View上的多个同时进行的动画效果,例如我们可以将
- ViewPropertyAnimator.animate(mDownView)
- .translationX(dismissRight ? mViewWidth : -mViewWidth)//X轴方向的移动距离
- .alpha(0)
- .setDuration(mAnimationTime)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- //Item滑出界面之后执行删除
- performDismiss(mDownView, mDownPosition);
- }
- });
替换成
- AnimatorSet set = new AnimatorSet();
- set.playTogether(ObjectAnimator.ofFloat(mDownView, "translationX", dismissRight ? mViewWidth : -mViewWidth),
- ObjectAnimator.ofFloat(mDownView, "alpha", 0));
- set.setDuration(mAnimationTime).start();
- set.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- //Item滑出界面之后执行删除
- performDismiss(mDownView, mDownPosition);
- }
- });
在效果上面是一样的,但是ViewPropertyAnimator在性能上要比使用ObjectAnimator来实现多个同时进行的动画要高的多,举个例子,假如要对View使用移动和透明度的动画,使用ViewPropertyAnimator的话,某个时间点上我们只需要调用一次invalidate()方法刷新界面就行了,而使用ObjectAnimator的话,移动的动画需要调用invalidate(),透明度的动画也需要调用invalidate()方法,在性能上使用AnimationSet比ViewPropertyAnimator要低,但是有的时候我们还是需要使用ObjectAnimator,比如,在某个时间内,我们需要将View先变大在变小在变大等复杂情况,这时候ObjectAnimator就派上用场了,例如
- ObjectAnimator.ofInt(mDownView, "scaleX", 0 ,100 ,0, 100).setDuration(100).start()
通过上面的几步我们就实现了ListView的左右滑动删除item的效果啦,但是还有一个效果,item删除之后,ListView的其他item向上或者向下缓缓滑动的效果,实现这个也很容易,就是动态设置item的高度,item高度逐渐变小,这样其他的item就会出现向上或者向下挤压的效果啦!
4. 这里我们使用的是ValueAnimator这个类,这个类并不是针对View作用的动画,而是对某个值作用的动画,他默认使用的Interpolator(插补器)是AccelerateDecelerateInterpolator(开始和结束的时候慢,中间快) , 举个很简单的例子,我们在10秒内使用ValueAnimator将某个值从0变化到100,如果使用LinearInterpolator(线性插补器,匀速变化)在第2秒的时候,这个值变成了20,而是用AccelerateDecelerateInterpolator,可能在第二秒的时候这个值为15或者13,所以我们在ValueAnimator变化的时候设置值动画变化的监听器AnimatorUpdateListener就知道某个时间这个值变成了多少,从而对View的某个属性进行设置(例如大小),所以ValueAnimator是间接的对View设置动画的
了解了ValueAnimator的使用原理,我们就可以现实上面的动画效果了,我们使用ValueAnimator将item的高度变成0,设置ValueAnimator变化的监听,我们在回调函数onAnimationUpdate()中动态的设置item的高度, 然后添加AnimatorListener监听动画的状态(例如动画开始,结束,重复等)监听,在动画结束的回调函数onAnimationEnd()中删除该item的数据,调用notifyDataSetChanged刷新ListView,看看下面这段代码
- ViewHelper.setAlpha(dismissView, 1f);
- ViewHelper.setTranslationX(dismissView, 0);
- ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
- lp.height = originalHeight;
- dismissView.setLayoutParams(lp);
我们使用动画只是将item移动出了屏幕,并且将item的高度设置为了0,并没有将item的View从ListView中Remove掉,况且ListView也不能直接Remove掉Item的,只能将数据源删除,在调用notifyDataSetChanged()刷新,所以我们需要将刚刚滑出屏幕高度设置为0的Item恢复回来
自定义控件的代码我们已经编写完了,接下来我们就要使用它了,先看界面的布局代码
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <com.example.swipedismisslistview.SwipeDismissListView
- android:id="@+id/swipeDismissListView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:listSelector="@android:color/transparent"
- android:cacheColorHint="@android:color/transparent">
- </com.example.swipedismisslistview.SwipeDismissListView>
- </RelativeLayout>
很简单,一个RelativeLayout包裹我们自定义的ListView控件,接下来就是主界面的代码编写,跟平常的ListView使用一样,但是我们需要设置OnDismissCallback()监听,在
onDismiss()中删除该位置对于的数据,刷新ListView
- package com.example.swipedismisslistview;
- import java.util.ArrayList;
- import java.util.List;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.ArrayAdapter;
- import android.widget.Toast;
- import com.example.swipedismisslistview.SwipeDismissListView.OnDismissCallback;
- public class SwipeActivity extends Activity {
- private SwipeDismissListView swipeDismissListView;
- private ArrayAdapter<String> adapter;
- private List<String> dataSourceList = new ArrayList<String>();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_swipe);
- init();
- }
- private void init() {
- swipeDismissListView = (SwipeDismissListView) findViewById(R.id.swipeDismissListView);
- for (int i = 0; i < 20; i++) {
- dataSourceList.add("滑动删除" + i);
- }
- adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_1,
- android.R.id.text1, dataSourceList);
- swipeDismissListView.setAdapter(adapter);
- swipeDismissListView.setOnDismissCallback(new OnDismissCallback() {
- @Override
- public void onDismiss(int dismissPosition) {
- adapter.remove(adapter.getItem(dismissPosition));
- }
- });
- swipeDismissListView.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view,
- int position, long id) {
- Toast.makeText(SwipeActivity.this, adapter.getItem(position), Toast.LENGTH_SHORT).show();
- }
- });
- }
- }
所有的代码都已经编写完毕了,接下来就是运行工程,看看具体的效果是不是我们想要的
好了,今天的讲解到这里结束了,有了NineOldAndroids我们可以在2.x的手机上面实现许多复杂的动画效果,文章也介绍了关于开源库NineOldAndroids使用的一些知识,文章有点长,希望读者还是先将文章看下,然后自己看看能不能自己实现出来,有什么不明白的地方请在下面留言,我会为大家解答的!
ps: 下载源码的时候运行出错,是因为我加入了NineOldAndroids的Jar包,然后又加入了NineOldAndroids工程库,主要是我写DEMO的时候为了方便看源码就导入了NineOldAndroids工程库,大家删除一个JAR包或者NineOldAndroids工程库 就能解决了
相关推荐
要实现左右滑动删除Item的功能,首先确保在项目中添加NineOldAndroids依赖。在build.gradle文件中添加以下依赖: ```groovy dependencies { implementation 'com.nineoldandroids:library:2.4.0' } ``` 接下来,...
"安卓Android源码——item可左右滑动的listview控件.zip" 包含了一个自定义的ListView实现,它允许用户通过左右滑动ListView的每个item来触发不同的操作,比如删除、标记等。 这个项目主要包含以下几个关键组件和...
总结来说,通过使用`SwipeListView`和`NineOldAndroids`库,开发者可以轻松地在ListView中实现项可左右滑动的交互,同时确保在各种Android版本上的兼容性。这不仅能提升用户的操作体验,也能让应用的界面更加生动和...
- 如果希望在快速滑动时添加更丰富的视觉效果,可以使用动画库,如Android的Animation框架或第三方库如NineOldAndroids,为滚动条添加平滑的过渡动画。 8. **注意的问题**: - 在处理滚动条时,需要注意避免滚动...
在这个场景下,如果你需要在更早的Android版本上实现类似效果,可以使用NineOldAndroids的ViewPropertyAnimator来替代Scroller实现滑动动画,其优点在于提供了更丰富的动画控制。 总的来说,实现ListView左右滑动...
标题中的“item可左右滑动的listview控件”指的是在Android开发中,一个具有滑动功能的ListView组件。在Android原生的ListView基础上,开发者通常会对其进行扩展,以实现更多的交互效果,如左右滑动。这样的控件常...
总的来说,通过结合`47deg-android-swipelistview`和`NineOldAndroids`这两个库,你可以实现ListView item的左右滑动功能,增加应用程序的交互性和功能性。在实际开发过程中,还需要注意性能优化,比如使用...
开发者可能使用自定义的ListView适配器和布局管理器,通过计算每个item的位置和速度,应用相应的Z轴偏移,使ListView中的每一项在滑动时呈现出立体效果。同时,可能还涉及到对每一项视图的深度阴影处理,增加3D的...
总的来说,SwipeListView为Android开发者提供了一种简单的方式来实现ListView的滑动删除功能,使得应用的用户体验更加丰富和直观。通过熟练掌握这个库,开发者可以快速地为自己的应用添加这一流行特性。
标题中的“android listview仿iphone特效”指的是在Android开发中,使用ListView组件实现类似iOS界面效果的一种技术。这种效果通常包括但不限于平滑滚动、动态高度调整、渐变背景等,目的是提升Android应用的用户...
这些可以通过Android的Animation API实现,或者使用第三方库如NineOldAndroids来支持老版本Android的动画。 8. **数据加载逻辑** - 刷新和加载更多的数据通常涉及到网络请求。可以使用HttpURLConnection、Volley、...
在数据交换后,使用ObjectAnimator或其他动画库,如NineOldAndroids,为被移动的item创建滑动动画。 6. **边界处理**:确保拖动过程中不会超出列表的边界,同时考虑在顶部和底部边缘拖动时的滚动效果。 7. **优化...
对于开发者来说,理解这些动画的实现机制至关重要,例如它们可能是基于开源动画库如NineOldAndroids或者使用了Android的Property Animation API来实现的。 动画库可能提供的功能包括但不限于: 1. 进入动画:当...
- 除了原生的Tween动画,开发者还可以使用第三方库如android-viewanimation或NineOldAndroids来实现更丰富的动画效果,这些库支持对Android早期版本的兼容。 8. **性能考虑**: - 在添加动画时,需要注意性能问题...
这可能需要使用到第三方库,如`android-viewbadger`来实现item的选中高亮,或者使用` NineOldAndroids`来实现对旧版Android的支持。 总的来说,这个例子展示了如何在Android中创建一个具有iOS风格的圆角ListView。...
注意,如果你的应用需要支持API 18以下的设备,可能需要使用NineOldAndroids库来实现动画效果。此外,对于不同屏幕尺寸和分辨率的设备,可能需要调整拖放范围和视觉反馈。 通过以上步骤,我们就能在ListView中实现...
在实际开发中,我们还可以利用第三方库,如NineOldAndroids支持在低版本设备上使用属性动画,Lottie库用于加载和播放Adobe After Effects导出的JSON动画文件,实现高级的图形动画效果。 在"Demo_Animation"这个...
除了Android自带的动画API,开发者还可以利用第三方动画库,如`android-anim-utils`、`NineOldAndroids`(用于兼容低版本Android)等,这些库提供了更多的动画效果和便捷的API,使得在ListView中实现动画更加简单。...
- **滑动手势检测**:使用`SwipeRefreshLayout`组件实现下拉刷新效果,或自定义手势检测实现上滑加载更多。 3. **Material Design**: - Google推出的Material Design设计语言提供了一系列规范和组件,如浮动操作...