首页 > 代码库 > 可删除超炫&多种特效的Card视图(改造自cardsui-for-android开源项目),提供DEMO下载

可删除超炫&多种特效的Card视图(改造自cardsui-for-android开源项目),提供DEMO下载

转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持!

      

这里贴几个效果图,我做了一个gif的动态图,但是不知道为什么上传后图片不动,所以只能放在相册里。

如果大家想看动态的图片演示请点击后面的链接gif动态演示图片

实例Demo下载地址在本文最后


简单介绍

这个Demo主要是使用了cardsui-for-android开源项目,并且做了一些优化和改进:

1.自定义card视图

2.添加长按事件,避免误操作

3.长按后可以删除card,并播放选中动画

4.删除后浮现一个悬浮button

5.点击悬浮button可以恢复之前删除的card视图


看内容前强烈建议先阅读以下的两篇文章,因为这个demo是在这两个文章的基础上写的:

关于cardsui-for-android这个开源项目的介绍和实现请看这篇博文酷炫开源项目cardsui-for-android-超详细源码分析,详解所用特效是如何实现的

4,5功能是参照开源项目cardslib,对这个开源项目的导入和简单介绍请看这篇博文开源项目cardslib简单介绍和导入eclipse并运行的方法


接下来对于以上的5个改进简单介绍:(本文只是提供一个思路,具体代码细节建议还是看提供的demo)


1.自定义card视图

这里只是简单的对于不同的card设置了不同的背景颜色:

CardStack stack = new CardStack(this);
		stack.setTitle("请支持大苞米的博客");
		
        for (int i = 0; i < 5; i++) {
        	MyCard card = null ;
            switch (i) {
                case 0:
                	card = new MyCard("#FFBB33");
                    break;
                case 1:
                	card = new MyCard("#98CC00");
                    break;
                case 2:
                	card = new MyCard("#A966CC");
                    break;
                case 3:
                	card = new MyCard("#33B4E4");
                    break;
                case 4:
                	card = new MyCard("#FF4343");
                    break;
            }
            stack.add(card);
        }
        mCardView.addStack(stack);
MyCard类就是我自定义的一个继承自card类的一个实现类,具体实现请看demo中的代码,很简单。可以很轻松的改成自己想要的样子,这里不过多介绍。


2.添加长按事件,避免误操作

3.长按后可以删除card,并播放选中动画

在CardStack中getView()方法中可以设置对card的点击监听

            //正常点击监听
            cardView.setOnClickListener(getClickListener(this, container, i));
            //长按点击监听
            cardView.setOnLongClickListener(getOnLongClickListener(card));
            //触摸监听
            cardView.setOnTouchListener(new SwipeDismissTouchListener(
                    cardView, card, i, new OnDismissCallback() {
                    	@Override
                        public void onDismiss(View view, Object token, int index) {
                    		....
                    	}
                    }
             }

长按点击监听getOnLongClickListener()的实现:

   //改监听传入被按的card作为引用
    private OnLongClickListener getOnLongClickListener(final Card card) {
    	return new OnLongClickListener() {

			@Override
			public boolean onLongClick(View v) {
				//给card设置一个flag,标识这个card被长按过了
				card.setLongClickable(true);
				//播放动画
				Animation shake = AnimationUtils.loadAnimation(mContext	, R.anim.shake);
				v.startAnimation(shake);
				return false;
			}
    	};
    }
这个动画是一个左右来回摆动的动画,具体实现可以去代码里找,这里不过多介绍了。

这里注意长按监听里最后返回false,这里在之前的那篇文章详介绍了,作用就是将事件接着交给ontouch监听处理。


接下来看看给card设好标识位后来到onTouchListener中,因为正常点击和长按点击都会触发触摸事件

	@Override
	public boolean onTouch(View view, MotionEvent motionEvent) {
		//按下
		case MotionEvent.ACTION_DOWN: {
			.....
			return false;
		}
		//抬起
		case MotionEvent.ACTION_UP: {
			
			if (dismiss && c.isLongClickable()) {
				....
			}
			//将长按标示置为初始false
			c.setLongClickable(false);
			
			break;
		}
		//滑动
		case MotionEvent.ACTION_MOVE: {
			
			if (mSwiping & c.isLongClickable()) {
				....
				return true;
			}
			break;
		}
	}
如上面的伪代码中,在滑动和抬起操作时先判断card中的长按标示。最后在抬起的时候将长按标示为重置为false,这样就实现了长按操作

4.删除后浮现一个悬浮button

如图:


首先要实现这个功能就要先知道删除事件在哪,这样才能添加相应功能。

if (dismiss && c.isLongClickable()) {
				// dismiss
				animate(mView)
						.translationX(dismissRight ? mViewWidth : -mViewWidth)
						.alpha(0).setDuration(mAnimationTime)
						.setListener(new AnimatorListener() {

							@Override
							public void onAnimationEnd(Animator arg0) {
								//执行删除操作
								performDismiss();

							}
						});
			} 

删除事件在上面介绍的触摸监听中滑动操作里面,如果可以删除,则先播放一段删除动画。在动画结束的回调方法中执行performDismiss()方法。该方法执行删除的回调方法mCallback.onDismiss(mView, mToken, mIndex);,该回调方法的具体实现在最开始为card设置触摸监听的地方。

cardView.setOnTouchListener(new SwipeDismissTouchListener(
                        cardView, card, i, new OnDismissCallback() {

                    @Override
                    public void onDismiss(View view, Object token, int index) {
                        Card c = (Card) token;
                        // call onCardSwiped() listener
                        c.OnSwipeCard();
                        cards.remove(c);
                        mAdapter.setItems(mStack, getPosition());

                        // refresh();
                        mAdapter.notifyDataSetChanged();
                        
                        //Check for a undo message to confirm
                        if (isEnableUndo() && mUndoBarController!=null){

                            //Show UndoBar
                            UndoCard itemUndo=new UndoCard(c , index);

                            if (mContext!=null){
                                Resources res = mContext.getResources();
                                if (res!=null){
                                	int number = index+1;
                                    String messageUndoBar = "确认要删除第"+number+"个card视图吗?";
                                    mUndoBarController.showUndoBar(
                                            false,
                                            messageUndoBar,
                                            itemUndo);
                                }
                            }

                        }
                    }
                }));

回调方法中先从cards集合中删除这个card。之后把这个删除的card和他的位置传递给UndoCard类,之后通过UndoBarController.showUndoBar方法来显示悬浮的点击按钮,这里传递的有显示的消息和携带了删除信息的UndoCard类。

之后来简单看下UndoBarController类:

public UndoBarController(View undoBarView, UndoListener undoListener,UndoBarUIElements undoBarUIElements) {
        mBarView = undoBarView;
        mBarAnimator = mBarView.animate();
        mUndoListener = undoListener;

        if (undoBarUIElements==null)
            undoBarUIElements = new DefaultUndoBarUIElements();
        mUndoBarUIElements = undoBarUIElements;

        mMessageView = (TextView) mBarView.findViewById(mUndoBarUIElements.getUndoBarMessageId());
        mBarView.findViewById(mUndoBarUIElements.getUndoBarButtonId())
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        hideUndoBar(false);
                        mUndoListener.onUndo(mUndoToken);
                    }
                });

        hideUndoBar(true);
    }

    @SuppressLint("NewApi")
	public void showUndoBar(boolean immediate, CharSequence message, Parcelable undoToken) {

        mUndoToken = undoToken;
        mUndoMessage = message;
        mMessageView.setText(mUndoMessage);

        mHideHandler.removeCallbacks(mHideRunnable);
        mHideHandler.postDelayed(mHideRunnable, 5000);

        mBarView.setVisibility(View.VISIBLE);
        if (immediate) {
            mBarView.setAlpha(1);
        } else {
            mBarAnimator.cancel();
            mBarAnimator
                    .alpha(1)
                    .setDuration(
                            mBarView.getResources()
                                    .getInteger(android.R.integer.config_shortAnimTime))
                    .setListener(null);
        }
    }

    @SuppressLint("NewApi")
	public void hideUndoBar(boolean immediate) {
        mHideHandler.removeCallbacks(mHideRunnable);
        if (immediate) {
            mBarView.setVisibility(View.GONE);
            mBarView.setAlpha(0);
            mUndoMessage = null;
            mUndoToken = null;

        } else {
            mBarAnimator.cancel();
            mBarAnimator
                    .alpha(0)
                    .setDuration(mBarView.getResources()
                            .getInteger(android.R.integer.config_shortAnimTime))
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            mBarView.setVisibility(View.GONE);
                            mUndoMessage = null;
                            mUndoToken = null;
                        }
                    });
        }
    }

这里主要关注showUndoBarhideUndoBarUndoBarController这3个方法

showUndoBar和hideUndoBar主要就是控制显示这个悬浮button,这个button的布局在代码中事先已经添加好,这两个方法中设置它的Visibility属性就可以控制隐藏和显示。


5.点击悬浮button可以恢复之前删除的card视图

接上面。UndoBarController方法中有一个监听器,可以监听悬浮button的点击事件:

 mBarView.findViewById(mUndoBarUIElements.getUndoBarButtonId())
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        hideUndoBar(false);
                        mUndoListener.onUndo(mUndoToken);
                    }
                });
点击后隐藏这个button,之后执行onUndo方法来恢复被删除的card。(mUndoToken中携带的就是被删除的Card还有他位置信息的UndoCard类)。


public interface UndoListener {
        /*
         *  Called when you undo the action
         */
        void onUndo(Parcelable undoToken);
    }
这个监听器是一个接口,下面要做的就是找到实现mUndoListener.onUndo(mUndoToken)这个监听回调方法的地方。

public class CardStack extends AbstractCard implements UndoBarController.UndoListener
实现这个接口的就是我们的CardStack这个类了,接下来在类中找到onUndo回调方法。

@Override
	public void onUndo(Parcelable undoToken) {
		//Restore items in lists (use reverseSortedOrder)
        if (undoToken != null) {

            UndoCard item = (UndoCard) undoToken;
            Card card = item.card;
            int position = item.position;

            if (card != null) {
               add(card, position);
               mAdapter.notifyDataSetChanged();
            }
        }
}
实现很简单:取出存放在UndoCard中的card和位置。把他重新添加到集合中,之后刷新适配器重新显示。


大概的对于这个开源项目的改进介绍完毕,本文只是提供一个思路,具体代码细节建议还是看提供的demo。

删除恢复功能是仿照cardsui这个开源项目实现的。涉及的类上面已经介绍了就是UndoCard和UndoBarController这两个类,

最后我强烈建议好好的看看这两个类和相关的调用方法,代码不多而且设计的很好,值得研究一下。。。

Demo下载地址:点击下载