所谓阻尼效果,什么是阻尼效果,好吧,我不知道怎么去描述它,看图吧,真相一看就懂(参看附件gif图)
此效果在iphone上非常常见,当列表滑动到顶部或者底部,没有内容时,列表跟随手指移动一定距离,android自身的listview是滑动到顶部或者底部时,会有一层淡淡的颜色,个人比较喜欢后者,但常常在项目中会有类似于前者的需求。仿爱疯,你懂的。
好了,这里我们在说一下可能需要主要到的地方:
1.手指滑动,listview中的item跟随手指滚动(如何做到?)
2.item移动的距离小于手指滑动的距离(这个好办)
3.手指抬起之后,listview自动滚回到顶部位置(怎么办呢?)
这里我还是在代码里面来说吧:
activity_main.xml
- <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" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:padding="@dimen/padding_medium"
- android:text="listview阻尼效果"
- android:id="@+id/textview"
- android:textSize="18sp"
- tools:context=".MainActivity" />
- <com.example.pulllistview.PullListView
- android:id="@+id/list"
- android:layout_width="fill_parent"
- android:layout_marginTop="10dp"
- android:layout_below="@+id/textview"
- android:layout_height="wrap_content" />
- <!-- <com.example.pulllistview.BounceListView
- android:id="@+id/list"
- android:layout_width="fill_parent"
- android:layout_marginTop="10dp"
- android:layout_below="@+id/textview"
- android:layout_height="wrap_content" /> -->
- </RelativeLayout>
PullListView.java
- package com.example.pulllistview;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.widget.ListView;
- /**自定义阻尼效果列表**/
- public class PullListView extends ListView implements Runnable {
- private float mLastDownY = 0f;
- private int mDistance = 0;
- private int mStep = 0;
- private boolean mPositive = false;
- private String Tag="PullListview";
- public PullListView (Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public PullListView (Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- public PullListView (Context context) {
- super(context);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN: //手指按下时触发
- Log.d(Tag,"ActionDown");
- if (mLastDownY == 0f && mDistance == 0) {
- mLastDownY = event.getY();
- Log.d(Tag,"mLastDownY赋值"+mLastDownY);
- return true;
- }
- break;
- case MotionEvent.ACTION_CANCEL:
- break;
- case MotionEvent.ACTION_UP: //手指抬起之后触发
- Log.d(Tag,"ActionUP");
- if (mDistance != 0) {
- System.out.println("---post");
- mStep = 1;
- mPositive = (mDistance >= 0);
- this.post(this);
- return true;
- }
- mLastDownY = 0f;
- mDistance = 0;
- break;
- case MotionEvent.ACTION_MOVE: //手指按下之后滑动触发
- Log.d(Tag,"ActionMove");
- if (mLastDownY != 0f) {
- mDistance = (int) (mLastDownY - event.getY());
- Log.d(Tag,"mLastDownY不为0,view跟随滑动"+"mDistance"+mDistance);
- if ((mDistance < 0 && getFirstVisiblePosition() == 0 &&
- getChildAt(0).getTop() == 0) || (mDistance > 0 &&
- getLastVisiblePosition() == getCount() - 1)) {
- //第一个位置并且是想下拉,就滑动或者最后一个位置向上拉
- //这个判断的作用是在非顶端的部分不会有此滚动
- mDistance /= 2; //这里是为了减少滚动的距离
- scrollTo(0, mDistance); //滚动
- return true;
- }
- }
- mDistance = 0;
- break;
- }
- return super.onTouchEvent(event);
- }
- public void run() {
- Log.d(Tag,"ActionUP调用post");
- mDistance += mDistance > 0 ? -mStep : mStep;
- scrollTo(0, mDistance);
- if ((mPositive && mDistance <= 0) || (!mPositive && mDistance >= 0)) {
- scrollTo(0, 0);
- mDistance = 0;
- mLastDownY = 0f;
- Log.d(Tag,"post中置0");
- return;
- }
- mStep += 1;
- // this.postDelayed(this, 10);
- this.post(this);
- }
- }
MainActivtiy.java
- package com.example.pulllistview;
- import java.util.ArrayList;
- import java.util.List;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.Menu;
- import android.widget.ArrayAdapter;
- public class MainActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- PullListView listview = (PullListView)findViewById(R.id.list);
- listview.setAdapter(new ArrayAdapter<String>(this,
- android.R.layout.simple_list_item_checked,getData()));
- }
- private List<String> getData(){
- List<String> data = new ArrayList<String>();
- data.add("阻尼效果测试数据1");
- data.add("阻尼效果测试数据2");
- data.add("阻尼效果测试数据3");
- data.add("阻尼效果测试数据4");
- data.add("阻尼效果测试数据5");
- data.add("阻尼效果测试数据6");
- data.add("阻尼效果测试数据7");
- data.add("阻尼效果测试数据8");
- data.add("阻尼效果测试数据9");
- data.add("阻尼效果测试数据10");
- data.add("阻尼效果测试数据11");
- data.add("阻尼效果测试数据12");
- data.add("阻尼效果测试数据13");
- return data;
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.activity_main, menu);
- return true;
- }
- }
此处再提供另一种方法,但需要leve 为2.3及之后的才能使用,原因之前的sdk尚未此方法。该方法非常简单,还是看源码先.
BounceListView.java
- package com.example.pulllistview;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.util.DisplayMetrics;
- import android.widget.ListView;
- public class BounceListView extends ListView{
- private static final int MAX_Y_OVERSCROLL_DISTANCE = 200;
- private Context mContext;
- private int mMaxYOverscrollDistance;
- public BounceListView(Context context){
- super(context);
- mContext = context;
- initBounceListView();
- }
- public BounceListView(Context context, AttributeSet attrs){
- super(context, attrs);
- mContext = context;
- initBounceListView();
- }
- public BounceListView(Context context, AttributeSet attrs, int defStyle){
- super(context, attrs, defStyle);
- mContext = context;
- initBounceListView();
- }
- private void initBounceListView(){
- //get the density of the screen and do some maths with it on the max overscroll
- distance variable so that you get similar behaviors no matter what the screen size
- final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
- final float density = metrics.density;
- mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE);
- }
- //主要就是这个方法了,直接重载复写就好
- @Override
- protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY,
- int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY,
- boolean isTouchEvent){
- //This is where the magic happens, we have replaced the incoming
- maxOverScrollY with our own custom variable mMaxYOverscrollDistance;
- return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
- scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent);
- }
- }