当前位置: 代码迷 >> Android >> QQ视差奇效和ListView侧滑删除
  详细解决方案

QQ视差奇效和ListView侧滑删除

热度:132   发布时间:2016-04-24 11:43:37.0
QQ视差特效和ListView侧滑删除

如图所示是效果图,当向下拉时,图片会被拉出来,松手后恢复。和ListView的侧滑删除

        

 

1.视差特效

首先图片是通过addHeaderView加上去的,所以在设置Adapter前先设置一个View来作为头布局,图片的设置android:scaleType="centerCrop"

然后可以重写ListView主要是用通过overScrollBy来实现图片的拉出效果的,当拉出图片绘制后,重写onTouchEvent方法MotionEvent.ACTION_UP

实现回弹

如下是主代码

 1 package com.demo.sb.main; 2  3 import com.demo.sb.adapter.ParallacAdapter; 4 import com.demo.sb.widget.MyParallaxListView; 5 import com.demo.suibian.R; 6  7 import android.app.Activity; 8 import android.os.Bundle; 9 import android.view.View;10 import android.view.Window;11 import android.view.ViewTreeObserver.OnGlobalLayoutListener;12 import android.widget.ImageView;13 14 /**15  * 视差特效类型于QQ空间上的16  * 17  * @author Administrator18  * 19  */20 public class MActivity_Parallac extends Activity {21 22     private MyParallaxListView mListView;23 24     @Override25     protected void onCreate(Bundle savedInstanceState) {26         // TODO Auto-generated method stub27         super.onCreate(savedInstanceState);28         requestWindowFeature(Window.FEATURE_NO_TITLE);29         setContentView(R.layout.mactivity_parallax);30 31         mListView = (MyParallaxListView) findViewById(R.id.lv);32         mListView.setOverScrollMode(View.OVER_SCROLL_NEVER);33         // 加上Header34         final View mHeaderView = View.inflate(MActivity_Parallac.this,35                 R.layout.viewheader, null);36         final ImageView mImage = (ImageView) mHeaderView.findViewById(R.id.iv);37         mListView.addHeaderView(mHeaderView);38 39         mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(40                 new OnGlobalLayoutListener() {41 42                     @Override43                     public void onGlobalLayout() {44                         // TODO Auto-generated method stub45                         mListView.setParallaxImage(mImage);46 47                         mHeaderView.getViewTreeObserver()48                                 .removeGlobalOnLayoutListener(this);49                     }50                 });51 52         // mListView.setAdapter(new SuibianAdapter(this));53         mListView.setAdapter(new ParallacAdapter(this));54     }55 }
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <ImageView        android:id="@+id/iv"        android:layout_width="match_parent"        android:layout_height="200dp"        android:contentDescription="@null"        android:scaleType="centerCrop"        android:src="@drawable/d" /></LinearLayout>
View Code

重写的ListView

  1 package com.demo.sb.widget;  2   3 import com.nineoldandroids.animation.ValueAnimator;  4 import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;  5   6 import android.content.Context;  7 import android.util.AttributeSet;  8 import android.util.Log;  9 import android.view.MotionEvent; 10 import android.view.animation.Animation; 11 import android.view.animation.OvershootInterpolator; 12 import android.view.animation.Transformation; 13 import android.widget.ImageView; 14 import android.widget.ListView; 15  16 public class MyParallaxListView extends ListView{ 17      18     private ImageView mImage; 19     private int drawableHeight; 20     private int mOriginalHeight; 21     public MyParallaxListView(Context context) { 22         super(context); 23         // TODO Auto-generated constructor stub 24     } 25      26     public MyParallaxListView(Context context, AttributeSet attrs) { 27         super(context, attrs); 28         // TODO Auto-generated constructor stub 29     } 30      31     public MyParallaxListView(Context context, AttributeSet attrs, int defStyle) { 32         super(context, attrs, defStyle); 33         // TODO Auto-generated constructor stub 34     } 35      36     /** 37      * 设置ImageView图片,拿到引用 38      * @param mImage 39      */ 40     public void setParallaxImage(ImageView mImage) { 41         // TODO Auto-generated method stub 42         this.mImage = mImage; 43         mOriginalHeight = mImage.getHeight(); 44         drawableHeight = mImage.getDrawable().getIntrinsicHeight(); 45          46         Log.d("jiejie", "height: " + mOriginalHeight + " drawableHeight: " + drawableHeight); 47     } 48  49     @Override 50     protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, 51             int scrollY, int scrollRangeX, int scrollRangeY, 52             int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) { 53         // TODO Auto-generated method stub 54         // deltaY : 竖直方向的瞬时偏移量 / 变化量 dx   顶部到头下拉为-, 底部到头上拉为+ 55         // scrollY : 竖直方向的偏移量 / 变化量 56         // scrollRangeY : 竖直方向滑动的范围 57         // maxOverScrollY : 竖直方向最大滑动范围 58         // isTouchEvent : 是否是手指触摸滑动, true为手指, false为惯性 59          60         Log.d("jiejie", "deltaY: " +deltaY + " scrollY: " + scrollY + " scrollRangeY: " + scrollRangeY 61                 + " maxOverScrollY: " + maxOverScrollY + " isTouchEvent: " + isTouchEvent); 62         //手指拉动并且是下拉 63         if(isTouchEvent && deltaY <0){ 64             //把拉动的瞬时变化量的绝对值交给Header,就可以实现放大的效果了 65             if(mImage.getHeight() <=drawableHeight ){ 66                 int newHeight = (int)(mImage.getHeight() + Math.abs(deltaY / 3.0f)); 67                 //高度不超过图片最大高度时,才让其生效 68                 mImage.getLayoutParams().height = newHeight; 69                 mImage.requestLayout(); 70             } 71         } 72          73         return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, 74                 scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); 75     } 76      77     @Override 78     public boolean onTouchEvent(MotionEvent ev) { 79         // TODO Auto-generated method stub 80          81         switch (ev.getAction()) { 82         case MotionEvent.ACTION_UP: 83             //执行回弹动画,方式一:属性动画 84             //从当前高度mImage.getHeight(),执行动画到原始高度mOriginalHeight 85             final int startHeight = mImage.getHeight(); 86             final int endHeight = mOriginalHeight; 87             //ValueAnimator(startHeight,endHeight); 88              89              90             //执行回弹动画,方式二:自定义Animation 91             ResetAnimation animation = new ResetAnimation(mImage,startHeight,endHeight); 92             startAnimation(animation); 93              94             break; 95  96         default: 97             break; 98         } 99         return super.onTouchEvent(ev);100     }101 102     private void ValueAnimator(final int startHeight, final int endHeight) {103         // TODO Auto-generated method stub104         ValueAnimator mValueAnimator = ValueAnimator.ofInt(1);105         mValueAnimator.addUpdateListener(new AnimatorUpdateListener() {106             107             @Override108             public void onAnimationUpdate(ValueAnimator arg0) {109                 // TODO Auto-generated method stub110                 float fraction = arg0.getAnimatedFraction();111                 //percent 0.0-1.0112                 Integer newHeight = evaluate(fraction, startHeight, endHeight);113                 114                 mImage.getLayoutParams().height = newHeight;115                 mImage.requestLayout();116             }117         });118         mValueAnimator.setInterpolator(new OvershootInterpolator());119         mValueAnimator.setDuration(800);120         mValueAnimator.start();121     }122     /**123      * 类型估值器124      * @param fraction125      * @param startValue126      * @param endValue127      * @return128      */129     public Integer evaluate(float fraction, Integer startValue, Integer endValue) {130         int startInt = startValue;131         return (int)(startInt + fraction * (endValue - startInt));132     }133     134     /**135      * 执行的动画136      * @author Administrator137      *138      */139     private class ResetAnimation extends Animation{140         141         private final ImageView mImageView;142         private final int startHeight;143         private final int endHeight;144 145         public ResetAnimation(ImageView mImage, int startHeight, int endHeight) {146             // TODO Auto-generated constructor stub147             this.mImageView = mImage;148             this.startHeight = startHeight;149             this.endHeight = endHeight;150             /**151              * Interpolator被用来修饰动画效果,定义动画的变化率,可以使存在的动画效果accelerated(加速)152              * decelerated(减速),repeated(重复),bounced(弹跳)等153              * 154              * OvershootInterpolator    向前甩一定值后再回到原来位置155              */156             setInterpolator(new OvershootInterpolator());157             //设置动画的执行时长158             setDuration(800);159         }160         @Override161         protected void applyTransformation(float interpolatedTime,162                 Transformation t) {163             // TODO Auto-generated method stub164             System.out.println(interpolatedTime );165             //interpolatedTime 0.0f -> 1.0f166             Integer newHeightInteger = evaluate(interpolatedTime, startHeight, endHeight);167             168             mImageView.getLayoutParams().height = newHeightInteger;169             mImageView.requestLayout();170             super.applyTransformation(interpolatedTime, t);171         }172     }173 }

2.实现ListView的侧滑删除功能

自定义的布局来显示侧滑的功能

  1 package com.demo.sb.adapter;  2   3 import com.demo.sb.utils.DensityUtil;  4   5 import android.content.Context;  6 import android.graphics.Rect;  7 import android.support.v4.view.ViewCompat;  8 import android.support.v4.widget.ViewDragHelper;  9 import android.util.AttributeSet; 10 import android.view.MotionEvent; 11 import android.view.View; 12 import android.widget.FrameLayout; 13  14 /** 15  * 侧拉删除控件 16  *  17  * @author Administrator 18  *  19  */ 20 public class SwipeLayout extends FrameLayout { 21  22     private Status status = Status.Close; 23     private OnSwipeLayoutListener swipeLayoutListener; 24  25     public Status getStatus() { 26         return status; 27     } 28  29     public void setStatus(Status status) { 30         this.status = status; 31     } 32  33     public OnSwipeLayoutListener getSwipeLayoutListener() { 34         return swipeLayoutListener; 35     } 36  37     public void setSwipeLayoutListener(OnSwipeLayoutListener swipeLayoutListener) { 38         this.swipeLayoutListener = swipeLayoutListener; 39     } 40  41     public static enum Status { 42         Close, Open, Draging 43     } 44  45     public static interface OnSwipeLayoutListener { 46         void onClose(SwipeLayout mSwipeLayout); 47  48         void onOpen(SwipeLayout mSwipeLayout); 49  50         void onDraging(SwipeLayout mSwipeLayout); 51  52         // 要去关闭 53         void onStartClose(SwipeLayout mSwipeLayout); 54  55         // 要去开启 56         void onStartOpen(SwipeLayout mSwipeLayout); 57     } 58  59     public SwipeLayout(Context context) { 60         this(context, null); 61         // TODO Auto-generated constructor stub 62     } 63  64     public SwipeLayout(Context context, AttributeSet attrs) { 65         this(context, attrs, 0); 66         // TODO Auto-generated constructor stub 67     } 68  69     public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { 70         super(context, attrs, defStyle); 71         // TODO Auto-generated constructor stub 72         mDragHelper = ViewDragHelper.create(this, 1.0f, mCallback); 73     } 74  75     ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() { 76         // c . 重写监听 77         @Override 78         public boolean tryCaptureView(View arg0, int arg1) { 79             // TODO Auto-generated method stub 80             return true; 81         } 82  83         // 限定移动范围 84         public int clampViewPositionHorizontal(View child, int left, int dx) { 85             // left 86             if (child == mFrontView) { 87                 if (left > 0) { 88                     return 0; 89                 } else if (left < -mRange) { 90                     return -mRange; 91                 } 92             } else if (child == mBackView) { 93                 if (left > mWidth) { 94                     return mWidth; 95                 } else if (left < mWidth - mRange) { 96                     return mWidth - mRange; 97                 } 98             } 99             return left;100         };101 102         public void onViewPositionChanged(View changedView, int left, int top,103                 int dx, int dy) {104             // 专递事件105             if (changedView == mFrontView) {106                 mBackView.offsetLeftAndRight(dx);107             } else if (changedView == mBackView) {108                 mFrontView.offsetLeftAndRight(dx);109             }110             despatchSwipeEvent();111 112             // 兼容老版本113             invalidate();114 115         };116 117         public void onViewReleased(View releasedChild, float xvel, float yvel) {118             if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) {119                 open();120             } else if (xvel < 0) {121                 open();122             } else {123                 close();124             }125         };126 127     };128 129     private ViewDragHelper mDragHelper;130     private View mBackView;131     private View mFrontView;132     private int mHeight;133     private int mWidth;134     private int mRange;135 136     // b. 专递触摸事件137     @Override138     public boolean onInterceptTouchEvent(MotionEvent ev) {139         // TODO Auto-generated method stub140         return mDragHelper.shouldInterceptTouchEvent(ev);141     }142 143     protected void despatchSwipeEvent() {144         // TODO Auto-generated method stub145         if (swipeLayoutListener != null) {146             swipeLayoutListener.onDraging(this);147         }148         // 记录上一次的状态149         Status preStatus = status;150         // 更新当前的状态151         status = updateStatus();152         if (preStatus != status && swipeLayoutListener != null) {153             if (status == Status.Close) {154                 swipeLayoutListener.onClose(this);155             } else if (status == Status.Open) {156                 swipeLayoutListener.onOpen(this);157             } else if (status == Status.Draging) {158                 if (preStatus == Status.Close) {159                     swipeLayoutListener.onStartOpen(this);160                 } else if (preStatus == Status.Open) {161                     swipeLayoutListener.onStartClose(this);162                 }163             }164         }165     }166 167     private Status updateStatus() {168 169         int left = mFrontView.getLeft();170         if (left == 0) {171             return Status.Close;172         } else if (left == -mRange) {173             return Status.Open;174         }175         return Status.Draging;176     }177 178     public void close() {179         // TODO Auto-generated method stub180         DensityUtil.showToast(getContext(), "Close");181         close(true);182     }183 184     public void close(boolean isSmooth) {185         // TODO Auto-generated method stub186         int finalLeft = 0;187         if (isSmooth) {188             // 开始动画189             if (mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)) {190                 ViewCompat.postInvalidateOnAnimation(this);191             }192         } else {193             layoutContent(false);194         }195     }196 197     public void open() {198         DensityUtil.showToast(getContext(), "Open");199         open(true);200     }201 202     public void open(boolean isSmooth) {203         int finalLeft = -mRange;204         if (isSmooth) {205             // 开始动画206             if (mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)) {207                 ViewCompat.postInvalidateOnAnimation(this);208             }209         } else {210             layoutContent(true);211         }212     }213 214     @Override215     public void computeScroll() {216         // TODO Auto-generated method stub217         super.computeScroll();218 219         if (mDragHelper.continueSettling(true)) {220             ViewCompat.postInvalidateOnAnimation(this);221         }222     }223 224     @Override225     public boolean onTouchEvent(MotionEvent event) {226         // TODO Auto-generated method stub227         try {228             mDragHelper.processTouchEvent(event);229         } catch (Exception e) {230             e.printStackTrace();231         }232         return true;233     }234 235     @Override236     protected void onLayout(boolean changed, int left, int top, int right,237             int bottom) {238         // TODO Auto-generated method stub239         super.onLayout(changed, left, top, right, bottom);240         // 摆放位置241         layoutContent(false);242     }243 244     private void layoutContent(boolean isOpen) {245         // TODO Auto-generated method stub246         // 摆放钱View247         Rect frontRect = computeFrontViewRect(isOpen);248         mFrontView.layout(frontRect.left, frontRect.top, frontRect.right,249                 frontRect.bottom);250         // 摆放后View251         Rect backRect = computeBackViewViaFront(frontRect);252         mBackView.layout(backRect.left, backRect.top, backRect.right,253                 backRect.bottom);254 255         // 调整顺序,把mFrontView前置256         bringChildToFront(mFrontView);257     }258 259     private Rect computeBackViewViaFront(Rect frontRect) {260         // TODO Auto-generated method stub261         int left = frontRect.right;262         return new Rect(left, 0, left + mRange, 0 + mHeight);263     }264 265     private Rect computeFrontViewRect(boolean isOpen) {266         // TODO Auto-generated method stub267         int left = 0;268         if (isOpen) {269             left = -mRange;270         }271         return new Rect(left, 0, left + mWidth, 0 + mHeight);272     }273 274     @Override275     protected void onFinishInflate() {276         // TODO Auto-generated method stub277         super.onFinishInflate();278         mBackView = getChildAt(0);279         mFrontView = getChildAt(1);280     }281 282     @Override283     protected void onSizeChanged(int w, int h, int oldw, int oldh) {284         // TODO Auto-generated method stub285         super.onSizeChanged(w, h, oldw, oldh);286         mHeight = mFrontView.getMeasuredHeight();287         mWidth = mFrontView.getMeasuredWidth();288 289         mRange = mBackView.getMeasuredWidth();290     }291 292 }
  1 package com.demo.sb.adapter;  2   3 import java.util.ArrayList;  4   5 import com.demo.sb.adapter.SwipeLayout.OnSwipeLayoutListener;  6 import com.demo.sb.utils.DensityUtil;  7 import com.demo.suibian.R;  8   9 import android.app.AlertDialog; 10 import android.content.Context; 11 import android.content.DialogInterface; 12 import android.view.View; 13 import android.view.ViewGroup; 14 import android.widget.BaseAdapter; 15 import android.widget.TextView; 16  17 public class ParallacAdapter extends BaseAdapter { 18  19     private Context context; 20     private int[] cost = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; 21     private String[] nameStrings = { "宋江", "卢俊义", "吴用", "公孙胜", "关胜", "林冲", 22             "秦明", "呼延灼", "花荣", "柴进", "李应", "鲁智深", "索超", "戴宗" }; 23     private ArrayList<SwipeLayout> opendItems; 24  25     public ParallacAdapter(Context context) { 26         super(); 27         this.context = context; 28  29         opendItems = new ArrayList<SwipeLayout>(); 30     } 31  32     @Override 33     public int getCount() { 34         // TODO Auto-generated method stub 35         return nameStrings.length; 36     } 37  38     @Override 39     public Object getItem(int arg0) { 40         // TODO Auto-generated method stub 41         return nameStrings[arg0]; 42     } 43  44     @Override 45     public long getItemId(int arg0) { 46         // TODO Auto-generated method stub 47         return arg0; 48     } 49  50     @Override 51     public View getView(final int arg0, View arg1, ViewGroup arg2) { 52         // TODO Auto-generated method stub 53         ViewHolder holder; 54         if (arg1 == null) { 55             holder = new ViewHolder(); 56             arg1 = View.inflate(context, R.layout.item_parallac_list, null); 57             holder.tv_del = (TextView) arg1.findViewById(R.id.tv_item_pardel); 58             holder.tv_name = (TextView) arg1 59                     .findViewById(R.id.item_parallax_name); 60             holder.tv_fight = (TextView) arg1 61                     .findViewById(R.id.item_parallax_fight); 62             holder.tv_call = (TextView) arg1.findViewById(R.id.tv_item_parcall); 63             arg1.setTag(holder); 64         } else { 65             holder = (ViewHolder) arg1.getTag(); 66         } 67  68         SwipeLayout sLayout = (SwipeLayout) arg1; 69         sLayout.setSwipeLayoutListener(new OnSwipeLayoutListener() { 70  71             @Override 72             public void onStartOpen(SwipeLayout mSwipeLayout) { 73                 // TODO Auto-generated method stub 74                 // 要去开启时,先遍历所有已打开的条目,逐个关闭 75                 for (SwipeLayout layout : opendItems) { 76                     layout.close(); 77                 } 78                 opendItems.clear(); 79             } 80  81             @Override 82             public void onStartClose(SwipeLayout mSwipeLayout) { 83                 // TODO Auto-generated method stub 84  85             } 86  87             @Override 88             public void onOpen(SwipeLayout mSwipeLayout) { 89                 // TODO Auto-generated method stub 90                 opendItems.add(mSwipeLayout); 91             } 92  93             @Override 94             public void onDraging(SwipeLayout mSwipeLayout) { 95                 // TODO Auto-generated method stub 96  97             } 98  99             @Override100             public void onClose(SwipeLayout mSwipeLayout) {101                 // TODO Auto-generated method stub102                 opendItems.remove(mSwipeLayout);103             }104         });105         holder.tv_name.setText("名字为 :" + nameStrings[arg0]);106         holder.tv_fight.setText("战斗力: " + cost[arg0]);107         holder.tv_del.setOnClickListener(new View.OnClickListener() {108 109             @Override110             public void onClick(View view) {111                 // TODO Auto-generated method stub112                 DensityUtil.showToast(context, "第" + arg0 + "个     为"113                         + nameStrings[arg0]);114             }115         });116         holder.tv_call.setOnClickListener(new View.OnClickListener() {117 118             @Override119             public void onClick(View view) {120                 // TODO Auto-generated method stub121                 AlertDialog.Builder builder = new AlertDialog.Builder(context);122                 builder.setTitle("标题!!!");123                 builder.setCancelable(false);124                 builder.setMessage("设置警告,是否确定删除,删除是不可逆的奥");125                 builder.setPositiveButton("确定",126                         new DialogInterface.OnClickListener() {127 128                             @Override129                             public void onClick(DialogInterface perent, int arg1) {130                                 // TODO Auto-generated method stub131                                 DensityUtil.showToast(context,132                                         nameStrings[arg0]);133                             }134                         });135                 builder.setNegativeButton("取消",136                         new DialogInterface.OnClickListener() {137 138                             @Override139                             public void onClick(DialogInterface arg0, int arg1) {140                                 // TODO Auto-generated method stub141 142                             }143                         });144                 builder.create().show();145             }146         });147         return arg1;148     }149 150     static class ViewHolder {151         TextView tv_del;152         TextView tv_name;153         TextView tv_fight;154         TextView tv_call;155     }156 }
<?xml version="1.0" encoding="utf-8"?><com.demo.sb.adapter.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/sl"    android:layout_width="match_parent"    android:layout_height="80dp"    android:background="#4000" >    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:orientation="horizontal" >        <TextView            android:id="@+id/tv_item_parcall"            android:layout_width="100dp"            android:layout_height="match_parent"            android:background="#666"            android:gravity="center"            android:text="call"            android:textColor="#fff" />        <TextView            android:id="@+id/tv_item_pardel"            android:layout_width="100dp"            android:layout_height="match_parent"            android:background="#f00"            android:gravity="center"            android:text="Delete"            android:textColor="#fff" />    </LinearLayout>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="#4fff"        android:padding="5dp" >        <ImageView            android:id="@+id/item_view"            android:layout_width="80dp"            android:layout_height="80dp"            android:contentDescription="@null"            android:scaleType="fitXY"            android:src="@drawable/a" />        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:orientation="vertical"            android:padding="10dp" >            <TextView                android:id="@+id/item_parallax_name"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:textColor="#f00"                android:textSize="20sp" />            <TextView                android:id="@+id/item_parallax_fight"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:paddingTop="10dp"                android:text=""                android:textColor="#5000"                android:textSize="16sp" />        </LinearLayout>    </LinearLayout></com.demo.sb.adapter.SwipeLayout>
View Code

 

  相关解决方案