Reprinted please indicate this article from xiaanming blog (http://blog.csdn.net/xiaanming/article/details/18311877), please respect others' hard work results, thank you!
Today, we will write custom controls to customize the effect of sliding the left and right sides of a ListView to delete items. This effect has been achieved before, if you are interested, you can see that Android uses Scroller to achieve the brilliant effect of sliding the left and right sides of the ListView to delete items. Previously, it was implemented using the sliding class Scroller, however, after reading the left and right sliding deletion effects on the notification bar, it is really great. When we slide more than half of the items, the transparency of the items changes to 0, we knew that the item was deleted when we raised our finger. When the transparency of the item was not 0, we lifted our finger and the Item would return to the starting position, in this way, we will know where the item will be deleted, where the Item will not be deleted, and the user experience is better. Another effect is that when we slide and delete the item, other items in ListView will scroll up or down, and it feels great. So I searched on GitHub and found that many open source libraries have this effect, such as ListViewAnimations, and Roid-swipelistview and so on. I have read the implementation principle and used the open-source library NineOldAndroids of the animation of Jake Wharton. What did this library do? In API3.0 (Honeycomb), the SDK adds an android. the class in the animation package is related to the implementation of animation effects. The Honeycomb API can be used to achieve very complex animation effects. However, if a developer wants to use this API in less than 3.0, we need to use the open-source framework Nine Old Androids. In this library, we will judge the SDK version based on the running machine. If it is API3.0 or above, we will use the animation class that comes with Android, otherwise, use the Nine Old Androids library. This is a compatible library. Let's take a look at the specific implementation of this effect.
Main Idea of achieving this effect
The general idea is this four steps. Some of the details will be answered one by one. Let's use the code to achieve this effect.
First, create a project called Swipedismisslistview. We need to introduce the library Nine Old Androids to the project.
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 and Roid. 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 SwipeDism IssListView extends ListView {/*** considers it as the minimum sliding distance */private int mSlop;/*** minimum Sliding Speed */private int mMinFlingVelocity; /*** maximum Sliding Speed */private int mMaxFlingVelocity;/***** animation execution time */protected long mAnimationTime = 150; /*** indicates whether the user is sliding */private boolean mSwiping;/*** sliding speed detection class */private VelocityTracker mVelocityTracker; /*** position pressed by the finger */private int mDownPosition;/*** View corresponding to the item pressed */private View MDownView; private float mDownX; private float mDownY;/*** item width */private int mViewWidth; /*** when the ListView Item slides out of the interface callback interface */private OnDismissCallback onDismissCallback;/***** set the animation time ** @ param mAnimationTime */public void setmAnimationTime (long mAnimationTime) {this. mAnimationTime = mAnimationTime;}/*** set the deletion callback interface ** @ param onDismissCallback */public void setOnDismissCallback (OnDismissCallback onDi SmissCallback) {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. getSca LedTouchSlop (); mMinFlingVelocity = vc. getScaledMinimumFlingVelocity () * 8; // get the minimum sliding speed. mMaxFlingVelocity = vc. getScaledMaximumFlingVelocity (); // get the maximum Sliding Speed} @ Overridepublic 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;} r Eturn super. onTouchEvent (ev);}/*** press event processing ** @ 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 ();} // Add speed detection mVelocityTracker = VelocityTracker. obtain (); mVelocityTracker. addMovement (ev);}/*** method for processing finger sliding ** @ param ev * @ return */private boolean handleActionMove (MotionEvent ev) {if (mVelocityTracker = null | mDownView = null) {return super. onTouchEvent (ev);} // obtains the float deltaX = ev distance from X. getX ()-mDownX; float deltaY = ev. getY ()-mDownY; // The sliding distance in the X direction is greater than mS. If (Math. abs (deltaX)> mSlop & Math. abs (deltaY) <mSlop) {mSwiping = true; // when the finger slides the item, the Click Event of the item is canceled, otherwise, we will slide the Item along with the occurrence of the item Click Event MotionEvent cancelEvent = MotionEvent. obtain (ev); cancelEvent. setAction (MotionEvent. ACTION_CANCEL | (ev. getActionIndex () <MotionEvent. ACTION_POINTER_INDEX_SHIFT); onTouchEvent (cancelEvent);} if (mSwiping) {// with whom the finger moves itemViewHelper. setTranslationX (mD OwnView, deltaX); // transparency gradient ViewHelper. setAlpha (mDownView, Math. max (0f, Math. min (1f, 1f-2f * Math. abs (deltaX)/mViewWidth); // when the finger slides, true is returned, indicating that SwipeDismissListView processes onTouchEvent by itself, and the others are handed over to the parent class to process return true ;} return super. onTouchEvent (ev);}/*** handle events raised by fingers * @ param ev */private void handleActionUp (MotionEvent ev) {if (mVelocityTracker = null | mDownView = null |! MSwiping) {return;} float deltaX = ev. getX ()-mDownX; // calculates the speed of X and Y based on the sliding distance. computeCurrentVelocity (1000); float velocityX = Math. abs (mVelocityTracker. getXVelocity (); float velocityY = Math. abs (mVelocityTracker. getYVelocity (); boolean dismiss = false; // whether the item needs to slide out of the screen boolean dismissRight = false; // whether to delete it to the right // if the distance between the dragged item is greater than half of the item, item slides out of the screen if (Math. abs (deltaX)> mViewWidth/2) {dismiss = true; d IsmissRight = deltaX> 0; // the speed at which the finger slides on the screen is within a certain range, also enables the item to slide out of the screen} else if (mMinFlingVelocity <= velocityX & velocityX <= mMaxFlingVelocity & velocityY <velocityX) {dismiss = true; dismissRight = mvelocity. getXVelocity ()> 0;} if (dismiss) {ViewPropertyAnimator. animate (mDownView ). translationX (dismissRight? MViewWidth:-mViewWidth) // The moving distance from the X axis. alpha (0 ). setDuration (mAnimationTime ). setListener (new AnimatorListenerAdapter () {@ Overridepublic void onAnimationEnd (Animator animation) {// Delete javasmdismiss (mDownView, mDownPosition) after the Item slides out of the interface );}});} else {// slide the item to the start position of ViewPropertyAnimator. animate (mDownView ). translationX (0 ). alpha (1 ). setDuration (mAnimationTime ). setListener (null);} // if (mVelocityTracker! = Null) {mVelocityTracker. recycle (); mVelocityTracker = null;} mSwiping = false;}/*** after the item is deleted in this method, the other items scroll up or down, and call back position to method onDismiss () * @ param dismissView * @ param dismissPosition */private void descrimdismiss (final View dismissView, final int dismissPosition) {final ViewGroup. layoutParams lp = dismissView. getLayoutParams (); // get the layout parameter final int originalHeight = dismissView of the item. getHeight (); // The height of the item ValueAnimator animator = ValueAnimator. ofInt (originalHeight, 0 ). setDuration (mAnimationTime); animator. start (); animator. addListener (new AnimatorListenerAdapter () {@ Overridepublic void onAnimationEnd (Animator animation) {if (onDismissCallback! = Null) {onDismissCallback. onDismiss (dismissPosition);} // This code is very important, because we have not removed the item from the ListView, the height of the item is set to 0 // so we will set the item back to ViewHelper after the animation is executed. setAlpha (dismissView, 1f); ViewHelper. setTranslationX (dismissView, 0); ViewGroup. layoutParams lp = dismissView. getLayoutParams (); lp. height = originalHeight; dismissView. setLayoutParams (lp) ;}}); animator. addUpdateListener (new ValueAnimator. animatorUpdateListener () {@ Overridepublic void onAnimationUpdate (ValueAnimator valueAnimator) {// the effect of this Code is that after ListView deletes an item, the effects of moving other items upward are lp. height = (Integer) valueAnimator. getAnimatedValue (); dismissView. setLayoutParams (lp) ;}}) ;}/ *** Delete callback interface ** @ author xiaanming **/public interface OnDismissCallback {public void onDismiss (int dismissPosition );}}You can see that the custom SwipeDismissListView only overwrites the onTouchEvent () method when Android uses Scroller to achieve the brilliant effect of sliding the left and right sides of the ListView to delete items, in fact, we can rewrite this method to achieve the desired effect.
1. let's first look at handleActionDown (), the processing method for pressing the screen by fingers. In this method, the position we clicked is obtained based on the point pressed by our fingers, and then the position we clicked is obtained using the pointToPosition () method, and getChildAt () to get the View object of the item we press, and add the finger to the screen sliding speed check, this step is relatively simple
2. the next step is handleActionMove (), the processing method for sliding fingers on the screen, which is a little more complicated, based on the sliding distance between the fingers on the X axis and the sliding distance of the Y axis, we can determine whether the horizontal sliding of the ListView item or the upstream and downstream sliding of the ListView can meet the condition of Math. abs (deltaX)> mSlop & Math. abs (deltaY) <mSlop, we use a Boolean value mSwiping to mark the Item in the horizontal sliding State. At this time, we need to deal with the logic of sliding the Item following the finger, we use ViewHelper to process the sliding logic of items. This class will determine whether to use the Android system API or the API implemented in NineOldandroids to make the View slide Effect Based on the SDK version of the machine, nineOldandroids mainly uses Camera (classes that can implement various complex animation effects). We directly use setTranslationX () and setAlpha () of ViewHelper to achieve the effect of item sliding and transparency gradient, to prevent the ListView from scrolling up or down when sliding an item, we must return true to prevent the ListView from scrolling up or down. Here we need to be very familiar with the event distribution mechanism of Android, I will not explain it here. If you are not familiar with it, go to the Internet to find relevant articles.
3. handleActionUp () is the processing method when the finger is lifted. It determines whether the Item slides out of the screen or slides to the starting position based on the sliding speed of the finger or the moving distance of the Item, in addition, it is necessary to determine whether the item slides out of the screen to the left or right. The specific logic can be viewed by the code. I believe everyone can understand it.
Here I want to talk about the ViewPropertyAnimator class, which can better implement multiple animation functions for a View at the same time, of course, we can also use ObjectAnimator to use AnimatorSet to achieve multiple simultaneous animation effects on a View. For example, we can
ViewPropertyAnimator. animate (mDownView). translationX (dismissRight? MViewWidth:-mViewWidth) // The moving distance from the X axis. alpha (0 ). setDuration (mAnimationTime ). setListener (new AnimatorListenerAdapter () {@ Overridepublic void onAnimationEnd (Animator animation) {// Delete javasmdismiss (mDownView, mDownPosition) after the Item slides out of the interface );}});Replace
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 () {@ Overridepublic void onAnimationEnd (Animator animation) {// Delete javasmdismiss (mDownView, mDownPosition) after the Item slides out of the interface );}});The effects are the same, but ViewPropertyAnimator is much higher in performance than ObjectAnimator to achieve multiple simultaneous animations. For example, if you want to use a moving and transparent animation for the View and ViewPropertyAnimator, you only need to call the invalidate () method to refresh the interface at a certain time point, and use ObjectAnimator, the invalidate () method must be called for moving animations, and the invalidate () method must also be called for transparent animations. In terms of performance, the use of AnimationSet is lower than ViewPropertyAnimator, but sometimes we still need to use ObjectAnimator, for example, in a certain period of time, we need to increase the View first, then the View size, and so on. In this case, ObjectAnimator will be used. For example
ObjectAnimator.ofInt(mDownView, "scaleX", 0 ,100 ,0, 100).setDuration(100).start()
The previous steps show the effect of sliding the left and right sides of the ListView to delete items. However, after the items are deleted, the other items of the ListView slide up or down slowly, it is easy to achieve this, that is, to dynamically set the height of the item, the height of the item gradually becomes smaller, so that other items will be squashed up or down!
4. here we use the ValueAnimator class, which is not an animation for a View, but an animation for a value. It uses the Interpolator (plug-in) by default) accelerateDecelerateInterpolator (slow at the beginning and end, fast in the middle). For example, we use ValueAnimator to change a value from 0 to 100 in 10 seconds, if LinearInterpolator (linear plug-in, constant speed variation) is used for 2nd seconds, the value is 20, but AccelerateDecelerateInterpolator, which may be 15 or 13 in the second, therefore, when ValueAnimator is changed, we set the value animation listener AnimatorUpdateListener to know how much this value has changed at a time, so as to set a certain attribute of the View (such as the size ), therefore, ValueAnimator indirectly animations the View.
After understanding the usage principle of ValueAnimator, we can implement the above animation effect. We use ValueAnimator to change the height of the item to 0 and set the listener for ValueAnimator change. We will update () in the callback function onAnimationUpdate () to dynamically set the height of the item, and then add the AnimatorListener to listen to the animation status (for example, the animation starts, ends, repeats, etc.). The callback function onAnimationEnd () after the animation ends () and call yydatasetchanged to refresh the ListView.
ViewHelper.setAlpha(dismissView, 1f);ViewHelper.setTranslationX(dismissView, 0);ViewGroup.LayoutParams lp = dismissView.getLayoutParams();lp.height = originalHeight;dismissView.setLayoutParams(lp);
We only use an animation to move the item out of the screen and set the height of the item to 0 without removing the View of the item from the ListView, besides, ListView cannot Remove items directly. It can only delete the data source and call yydatasetchanged () to refresh the data source. Therefore, we need to restore the items with the screen height set to 0.
The custom control code has been compiled, and we will use it next. First, let's look at the layout code of the interface.
<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>
Very simple: A RelativeLayout package our custom ListView control. Next we will write the code on the main interface, which is the same as the usual ListView, but we need to set the OnDismissCallback () listener, in
In onDismiss (), delete the data for this location and refresh the 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; pub Lic class SwipeActivity extends Activity {private incluswipedismisslistview; private ArrayAdapter <String> adapter; private List <String> inclucelist = new ArrayList <String> (); @ Overrideprotected 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 ("slide Delete" + 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 () {@ Overridepublic void onDismiss (int dismissPosition) {adapter. remove (adapte R. getItem (dismissPosition) ;}}); swipeDismissListView. setOnItemClickListener (new OnItemClickListener () {@ Overridepublic void onItemClick (AdapterView <?> Parent, View view, int position, long id) {Toast. makeText (SwipeActivity. this, adapter. getItem (position), Toast. LENGTH_SHORT ). show ();}});}}All the code has been compiled, and the next step is to run the project to see if the specific effect is what we want.
Now, today's explanation is over. With NineOldAndroids, we can go to 2. x's mobile phone implements a lot of complex animation effects. The article also introduces some knowledge about the use of the open-source library NineOldAndroids. The article is a bit long. I hope readers will read the article first, then let's see if it can be implemented by ourselves. If you have any questions, please leave a message below. I will answer your questions!