首先,我们来看看效果:
其实效果还很糙,还需要完善,不过大致的功能就是这样子,如果你看到这里还没放弃的话,那么我们就开始吧!
�1:卡片滑动自然得有卡片,卡片是什么呢?我这里使用的是CardView,简单来说就是一个FrameLayout,但是它可以定义各种样式来实现圆角之类的效果,具体大家可以查查学习一下,我就不讲了,使用方法很简单,就和FrameLayout一样:
这里我们放了一个CardView,然后在里面放了一个TextView来显示内容
2:现在卡片有了,我们接着来实现RecyclerView,相信大家既然看这篇文章,对于RecyclerView肯定是使用过的,那我就不具体的讲如何使用RecyclerView了,简单来说就是三步:定义一个RecyclerView,设置Adapter,设置LayoutManager,那我们就可以先写出如下的代码:
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setAdapter(new MyAdapter(datas,this));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
我们可以运行一下,效果是�一张张卡片的列表:
3:那么如何实现卡片重叠的效果呢?这就需要我们自定义LayoutManager了,我们只需要重写里面的onLayoutChildren就行:
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
for(int i=0;i
我们只需将每个Child的 top,left设置为0�即可,这样每个卡片就都重叠在了一起。然后最后的if语句则是将下面的卡片缩小。(有关如何自定义LayoutManager大家�可以百度学习,基本上和自定义ViewGroup类似)
我们做完这些,运行一下,会发现只有一张卡片了,其余卡片都叠在下面,我这里就不贴图了。
4:我们现在要来实现卡片的拖动功能了,卡片拖动的功能需要重写RecyclerView的onTouchEvent,这样我们就需要自定义一个RecyclerView,直接继承自RecyclerView就可以了,onTouchEvent代码如下:
@Override
public boolean onTouchEvent(MotionEvent e) {
if (getChildCount() == 0) {
return super.onTouchEvent(e);
}
View view = getChildAt(getChildCount() - 1);
CardView topView = (CardView) view.findViewById(R.id.card_view);
CardView nextView = null;
if(getChildAt(getChildCount() - 2)!=null){
View view2 = getChildAt(getChildCount() - 2);
nextView = (CardView) view2.findViewById(R.id.card_view);
}
switch (e.getAction()){
case MotionEvent.ACTION_DOWN:
touchDownX = (int) e.getX();
touchDownY = (int) e.getY();
itemX = (int) topView.getX();
itemY = (int) topView.getY();
break;
case MotionEvent.ACTION_MOVE:
moveX = (int) e.getX();
moveY = (int) e.getY();
dx = moveX-touchDownX;
dy = moveY-touchDownY;
topView.setX(itemX+dx);
topView.setY(itemY+dy);
if(nextView!=null){
ViewGroup.LayoutParams params = topView.getLayoutParams();
int width = params.width/6;
float fraction = calcuFraction(Math.abs(dx),Math.abs(dy),width);
NextItemBig(nextView,fraction);
}
break;
case MotionEvent.ACTION_UP:
ViewGroup.LayoutParams params = topView.getLayoutParams();
int width = params.width/6;
int height = params.height/6;
Log.d("TAG", "width :"+width+'\n'+"height :"+height);
if(isOut(width,height)){
//Toast.makeText(mContext, "控件移出了", Toast.LENGTH_SHORT).show();
OutAnimation();
}else {
//Toast.makeText(mContext, "控件未移出", Toast.LENGTH_SHORT).show();
topView.setX(itemX);
topView.setY(itemY);
BackAnimation(topView);
}
break;
}
return super.onTouchEvent(e);
}
因为CardView本身周围会有�一些空白,加上getX获取的是View左上角的坐标,所以拖动我们用偏移量来做�,也就是你move时候坐标减去down时候的坐标,得到一个偏移量,再把控件的坐标加上这个偏移量即可。你会发现我在计算控件中心点位置的时候,将params.width除以了6,因为�我发现你params.width获得的大小是你在xml里面设置的大小的3倍(至于为什么我不清楚...),然后在取一半,就是6了。
5:在顶层卡片拖动的时候,接下来的卡片,�需要慢慢变大。我这里设置的是在偏移量大于卡片尺寸一半的时候就算移出范围了,所以我们用滑动的偏移量除以卡片尺寸的一半得到一个变化的值:
float calcuFraction(int dx,int dy,int width){
int distance = (int) Math.sqrt(dx*dx+dy*dy);
float fraction = 1+0.25f *(distance/width);
if(fraction>=1.25f){
return 1.25f;
}else if(fraction<=1){
return 1;
}
else {
return fraction;
}
}
再用这个值去设置�下一张卡片的Scale就可以得到一个缩放的效果(我这种实现缩放�没过渡...需要改进)
6:实现了拖动,我们就需要在卡片移出和未移出时做些�动作。未移出时,我们需要卡片有个回弹动画;移出时,我们就把卡片删掉。
未移出时:
private void BackAnimation(View view){
int centerX = Util.getScreenWidth(mContext)/2;
int centerY = Util.getScreenHeight(mContext)/2;
int curX = (int) (view.getX()+Util.dip2px(mContext,100));
int curY = (int) (view.getY()+Util.dip2px(mContext,100));
shakeAnimation(1,centerX,centerY,curX,curY);
}
public void shakeAnimation(int counts,int centerX,int centerY,int curX,int curY) {
Animation translateAnimation = new TranslateAnimation((centerX - curX) / 2, 0, (centerY - curY) / 2, 0);
translateAnimation.setInterpolator(new CycleInterpolator(counts));
translateAnimation.setDuration(200);
startAnimation(translateAnimation);
}
这里我们用TranslationAnimation就可以(我本意是往滑动的反方向回弹,但实际是只能左上�右下,需要改进...)
移出时:
private void OutAnimation() {
MyAdapter adapter = (MyAdapter) this.getAdapter();
adapter.delTopItem();
}
这里我在Adapter里定义了一个删除函数,可以删除最上面的卡片,直接调用即可
public void delTopItem() {
int position = getItemCount() - 1;
mData.remove(position);
notifyItemRemoved(position);
}```
7:好了,到这里我们基本的效果就都实现了,不过还是有很多问题的...我想做这个的原因是我早上看了一篇文章http://mp.weixin.qq.com/s/75Jonr8kQb073tLWad396Q
作者就是用RecyclerView实现了一个类似的效果,�于是我也想实现一下,不过思路�都是自己的,没有参考他的代码(所以才这么多问题吗...)
8:完整源码:
https://github.com/ChenTianSaber/AndroidSlideCard
谢谢大家忍受这篇博客
####最后的最后:
######感谢我可爱的女朋友。