五行代码实现 炫动滑动 卡片层叠布局,仿探探、人人影视订阅界面 简单&优雅:LayoutManager+ItemTouchHelper

转载请标明出处:

http://blog.csdn.net/zxt0601/article/details/53730908

本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)

代码传送门:喜欢的话,随手点个star。多谢

https://github.com/mcxtzhang/LayoutManagerDemo

概述

前几天看有人实现了仿人人美剧的订阅界面,不过在细节之处以及实现方式我个人认为都不是最佳的姿势。

于是我也动手撸了一个,还顺带撸了个探探的界面,先看GIF:

这里吐个槽,探探这种设计真的像皇帝翻牌子的感觉,不喜欢左滑,喜欢右滑。

人人影视版特点(需求):

  • 动画:最多可见的这四层,在顶层卡片滑动时,每一层都会位移&放大动画,有种补充到顶层的感觉
  • 动画:松手时,如果未被判定为删除,则会有顶层以下每一层卡片收缩回原位的动画。
  • 无限循环:模仿人人影视,顶层卡片被删除后,补充到最底层。

除上述动画特点,探探版特点(需求):

  • Roate的变化:左右滑动时,顶层卡片会慢慢旋转,到阈值max大概十五度。
  • Alpha的变化:左滑时顶层卡片的删除按钮会慢慢显现,右滑时爱心按钮会慢慢显现
  • 显然,松手时,以上动画也需要复位。

我们的效果,基本上和原版一致了,写起来怎么样呢?

我不是标题党,如标题所说:

  • 简单:思路简单清晰易理解
  • 优雅:性能没有任何隐患,LayoutManager只会加载显示屏幕上可见的数量的View
  • 快速:利用ItemTouchHelper处理拖拽&滑动删除逻辑,核心代码不超过50行。且经过封装,四行代码就可以用。

伸手党福利:

如果懒得看这么多文字只想用,直接移步gayhub,gradle导入相关文件or复制。然后如下,搞定。

        mRv.setLayoutManager(new OverLayCardLayoutManager());
        CardConfig.initConfig(this);
        ItemTouchHelper.Callback callback = new RenRenCallback(mRv, mAdapter, mDatas);
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
        itemTouchHelper.attachToRecyclerView(mRv);

而且我将一些参

数都以变量形式计算,这样就做到了可配置,假如老板让你一开始多显示几层卡片,例如6层,你只需要修改一个参数即可,效果如图:

正确的姿势

正确的姿势就是:

  • 利用LayoutManager实现卡片层叠布局,值得注意的是,只layout出界面上可能会看见的那些View。
  • 搭配ItemTouchHelper,它本身实现了拖拽&滑动删除逻辑,我们只需要在onChildDraw()中绘制动画和onSwiped()中处理数据集(循环or删除)。

所以本文也算是填了LayoutManger系列的坑,实现了一个酷炫效果的布局。

Let’s Go!

LayoutManager的实现卡片层叠

其实本例中的LayoutManager十分简单,因为ItemTouchHelper的存在,LayoutManager根本不需要处理它的滑动事件,而LayoutManager中最难写的就是在滑动时的View回收和复用,以及layoutView的处理。

关于LayoutManager的基础知识和铺垫,我就不再赘述,可参考我以前的文章:LayoutManager实现流式布局

唯一注意事项

但是即便如此,还是有一个唯一的注意事项。我们只layout出界面上可能会看见的那些View即可。

因为考虑到动画,所以是可能会看见

我们看人人美剧的界面:

初始化时,界面上可见三个View,我们分别起名:TopView,Top-1View,Top-2View。其中TopView完全可见,Top-1View,Top-2View只有下边缘可见。

如文首GIF,滑动TopView时,Top-1View,Top-2View开始慢慢放大,并且向上位移,直至填充至它们各自上层的View。这时候露出了Top-3View

所以我们在书写LayoutManageronLayoutChildren()方法时,只要layout出当前数据集最后四个View即可。

前文提到的参数配置如下:

包括一些配置

  • 界面最多显示几个View
  • 每一级View之间的Scale差异、translationY等等
public class CardConfig {
    //屏幕上最多同时显示几个Item
    public static int MAX_SHOW_COUNT;
    //每一级Scale相差0.05f,translationY相差7dp左右
    public static float SCALE_GAP;
    public static int TRANS_Y_GAP;

    public static void initConfig(Context context) {
        MAX_SHOW_COUNT = 6;
        SCALE_GAP = 0.05f;
        TRANS_Y_GAP = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, context.getResources().getDisplayMetrics());
    }
}

LayoutManager全部代码如下,布满注释,如果看不懂,建议阅读前置文章LayoutManger系列

public class OverLayCardLayoutManager extends RecyclerView.LayoutManager {
    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    }
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        detachAndScrapAttachedViews(recycler);
        int itemCount = getItemCount();
        if (itemCount >= MAX_SHOW_COUNT) {
            //从可见的最底层View开始layout,依次层叠上去
            for (int position = itemCount - MAX_SHOW_COUNT; position < itemCount; position++) {
                View view = recycler.getViewForPosition(position);
                addView(view);
                measureChildWithMargins(view, 0, 0);
                int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
                int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
                //我们在布局时,将childView居中处理,这里也可以改为只水平居中
                layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
                        widthSpace / 2 + getDecoratedMeasuredWidth(view),
                        heightSpace / 2 + getDecoratedMeasuredHeight(view));
                /**
                 * TopView的Scale 为1,translationY 0
                 * 每一级Scale相差0.05f,translationY相差7dp左右
                 *
                 * 观察人人影视的UI,拖动时,topView被拖动,Scale不变,一直为1.
                 * top-1View 的Scale慢慢变化至1,translation也慢慢恢复0
                 * top-2View的Scale慢慢变化至 top-1View的Scale,translation 也慢慢变化只top-1View的translation
                 * top-3View的Scale要变化,translation岿然不动
                 */

                //第几层,举例子,count =7, 最后一个TopView(6)是第0层,
                int level = itemCount - position - 1;
                //除了顶层不需要缩小和位移
                if (level > 0 /*&& level < mShowCount - 1*/) {
                    //每一层都需要X方向的缩小
                    view.setScaleX(1 - SCALE_GAP * level);
                    //前N层,依次向下位移和Y方向的缩小
                    if (level < MAX_SHOW_COUNT - 1) {
                        view.setTranslationY(TRANS_Y_GAP * level);
                        view.setScaleY(1 - SCALE_GAP * level);
                    } else {//第N层在 向下位移和Y方向的缩小的成都与 N-1层保持一致
                        view.setTranslationY(TRANS_Y_GAP * (level - 1));
                        view.setScaleY(1 - SCALE_GAP * (level - 1));
                    }
                }
            }
        }
    }

}

撸到这里,我们的静态界面已经成型,下面让我们动起来:

ItemTouchHelper实现炫动滑动:

ItemTouchHelper的基础知识,建议大家自行学习,网上文章很多,我简单介绍一下,

This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

It works with a RecyclerView and a Callback class, which configures what type of interactions

are enabled and also receives events when user performs these actions.

Depending on which functionality you support, you should override

{@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)} and / or

{@link Callback#onSwiped(ViewHolder, int)}.

翻译 + 总结:

这货是一个工具类,为RecyclerView扩展滑动消失(删除)和drag & drop效果的。

它需要和RecyclerView、Callback 一起工作。Callback 类里定义了 允许哪些交互,并且会接收到对应的交互事件

根据你需要哪种功能(滑动消失(删除)和drag & drop),你需要重写

Callback#onMove(RecyclerView, ViewHolder, ViewHolder)—–drag & drop

Callback#onSwiped(ViewHolder, int) 方法。 —–滑动消失(删除)

总结一下入门级用法如下,三个步骤:

  • 定义一个Callback:ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(int,int),这两个int分别代表要 监听哪几个方向上的拖拽、滑动事件。 常用:ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
  • 将Callback传给ItemTouchHelper:ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
  • 关联ItemTouchHelper和RecyclerView:itemTouchHelper.attachToRecyclerView(mRv)

这三个步骤做完后,ItemTouchHelper就会自动帮我们完成 滑动消失(删除)和drag & drop 的功能。

滑动删除

我们本例中,需要的是滑动消失(删除) ,所以我们的Callback不需要关注onMove()方法。

且我们需要上下左右滑动都可以删除的效果。

则如下构造Callback,传入上下左右:

ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(0,
                ItemTouchHelper.DOWN | ItemTouchHelper.UP | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT)

onSwiped()方法,是滑动删除动作已经发生后回调的,即,我们先滑动卡片,然后松手,此时ItemTouchHelper判断我们的手势是删除手势,会自动对这个卡片执行丢出屏幕外的动画,同时回调onSwiped()方法。

所以我们需要在其中如下写:

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                //★实现循环的要点
                SwipeCardBean remove = mDatas.remove(viewHolder.getLayoutPosition());
                mDatas.add(0, remove);
                mAdapter.notifyDataSetChanged();
            }

在这里我们完成了循环的操作:

  • 利用当前被删除的ViewViewHolder拿到Position
  • 删除数据集中对应Position的数据源
  • 同时将该数据源插入数据集中的首位。
  • 调用notifyDataSetChanged(),通知列表刷新

    如此我们便完成了,循环列表的需求

这里提一下为什么我们要调用notifyDataSetChanged()

看官方文档:

ItemTouchHelper moves the items’ translateX/Y properties to reposition them

即ItemTouchHelper实现的滑动删除,其实只是隐藏了这个滑动的View。并不是真的删除了。

LayoutManager实现流式布局一文第五节中,我们已经提到,notifyDataSetChanged()会回调onLayoutChildren()这个函数,而在这个函数中,我们会重新布局,即真正的移除(不再layout)滑动掉的View,同时会补充进新的最底层的View

嗯,JavaBean也看一眼吧,没亮点:

public class SwipeCardBean {
    private int postition;//位置
    private String url;
    private String name;
    }

我们写到这里已经完成了滑动删除的功能,其实我们什么都没有写是吧,复杂的判断都由ItemTouchHelper帮我们处理掉了,例如速度、滑动距离是否到达删除阈值,删除成功移除的动画、取消删除复位的动画等等。

所以我说利用ItemTouchHelper才是正确的姿势,因为很简单&快速。

下面我们来实现滑动时的动画。

滑动时动画

我们需要重写CallbackonChildDraw()方法,这个方法参数较多:

     * @param c                 The canvas which RecyclerView is drawing its children

     * @param recyclerView      The RecyclerView to which ItemTouchHelper is attached to

     * @param viewHolder        The ViewHolder which is being interacted by the User or it was
                                interacted and simply animating to its original position

     * @param dX                The amount of horizontal displacement caused by user‘s action

     * @param dY                The amount of vertical displacement caused by user‘s action

     * @param actionState       是拖拽还是滑动事件  The type of interaction on the View. Is either {@link #ACTION_STATE_DRAG} or {@link #ACTION_STATE_SWIPE}.  

     * @param isCurrentlyActive 事件是用户产生还是动画产生的 True if this view is currently being controlled by the user or false it is simply animating back to its original state.

对我们比较有用的有dX dX,可以判断滑动方向,以及计算滑动的比例,从而控制缩放、位移动画的程度

本文如下编写,对View的缩放、位移,其实是对LayoutManager里的操作的逆操作,值得注意的是最后一层,即top-3View在Y轴上是保持不变的:

@Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
                //先根据滑动的dxdy 算出现在动画的比例系数fraction
                double swipValue = Math.sqrt(dX * dX + dY * dY);
                double fraction = swipValue / getThreshold(viewHolder);
                //边界修正 最大为1
                if (fraction > 1) {
                    fraction = 1;
                }
                //对每个ChildView进行缩放 位移
                int childCount = recyclerView.getChildCount();
                for (int i = 0; i < childCount; i++) {
                    View child = recyclerView.getChildAt(i);
                    //第几层,举例子,count =7, 最后一个TopView(6)是第0层,
                    int level = childCount - i - 1;
                    if (level > 0) {
                        child.setScaleX((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP));

                        if (level < MAX_SHOW_COUNT - 1) {
                            child.setScaleY((float) (1 - SCALE_GAP * level + fraction * SCALE_GAP));
                            child.setTranslationY((float) (TRANS_Y_GAP * level - fraction * TRANS_Y_GAP));
                        }
                    }
                }
            }

getThreshold(viewHolder)函数,返回是否可以被回收掉的阈值,关于它为什么这么写,我是从源码里找到的,本末会讲解:

            //水平方向是否可以被回收掉的阈值
            public float getThreshold(RecyclerView.ViewHolder viewHolder) {
                return mRv.getWidth() * getSwipeThreshold(viewHolder);
            }

探探效果的实现

一开始文章撸到这里应该结束了,群里出来一个马小跳,告诉我探探和这略有不同,希望我一并实现。

嗯,好吧。表示没听说过探探,那我先去下载一个看看吧。

loading-install-open……..

哎哟呵,十分钟过去了,我还在滑动看美女 忘记了要干什么,被女票看到胖揍了我一顿。

好的,我捂着脸继续分析。

探探和人人影视有两点不同:

  • Roate的变化:左右滑动时,顶层卡片会慢慢旋转,到阈值max大概十五度。
  • Alpha的变化:左滑时顶层卡片的删除按钮会慢慢显现,右滑时爱心按钮会慢慢显现

感觉也是炒鸡简单,来吧。五分钟撸完吃外卖。修改点:

  • 在layout布局添加『 X 』&『 爱心 』。
  • onChildDraw()里,按比例修改TopView的Rotate & Alpha

监听方向

还有一点小不同,上滑下滑不再能删除,所以我们构造时只传入左右即可:

ItemTouchHelper.Callback callback = new ItemTouchHelper.SimpleCallback(0,
                ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) 

布局添加两个按钮

onChildDraw()

在上文人人影视的基础上扩展,上文的效果,对TopView是不做任何操作的。这里只需要再对TopView做额外操作即可:

            @Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
                ...
                for (int i = 0; i < childCount; i++) {
                    View child = recyclerView.getChildAt(i);
                    //第几层,举例子,count =7, 最后一个TopView(6)是第0层,
                    int level = childCount - i - 1;
                    if (level > 0) {
                        ...
                    } else {
                        //探探只是第一层加了rotate & alpha的操作
                        //不过他区分左右
                        float xFraction = dX / getThreshold(viewHolder);
                        //边界修正 最大为1
                        if (xFraction > 1) {
                            xFraction = 1;
                        } else if (xFraction < -1) {
                            xFraction = -1;
                        }
                        //rotate
                        child.setRotation(xFraction * MAX_ROTATION);

                        //自己感受一下吧 Alpha
                        if (viewHolder instanceof ViewHolder) {
                            ViewHolder holder = (ViewHolder) viewHolder;
                            if (dX > 0) {
                                //露出左边,比心
                                holder.setAlpha(R.id.iv_love, xFraction);
                            } else {
                                //露出右边,滚犊子
                                holder.setAlpha(R.id.iv_del, -xFraction);
                            }
                        }
                    }
                }
            }

实现完后,我以为结束了,结果比我们想象的还要复杂一丢丢。因为此时删除后,notifyDataSetChanged()刷新界面,而TopView还是倾斜的,爱心、删除图标也是出现的。这显然与预期不符。所以我们需要在onSwiped()里将其复位:

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            ...
                //探探只是第一层加了rotate & alpha的操作
                //对rotate进行复位
                viewHolder.itemView.setRotation(0);
                //自己感受一下吧 Alpha
                if (viewHolder instanceof ViewHolder) {
                    ViewHolder holder = (ViewHolder) viewHolder;
                    holder.setAlpha(R.id.iv_love, 0);
                    holder.setAlpha(R.id.iv_del, 0);
                }
            }

Ok,大功告成。效果和文首一样,尽情去跟产品UI嘚瑟吧。

阈值的寻找之路

阈值的寻找,花费了我一些时间,因为我想做到和系统的行为保持一致

即,当删除、喜欢图标全显,当Top-1View显示完毕时,松手 TopView会回收。

这就决定了我们的缩放、位移的阈值不能随便定,所以我们必须去源代码里找答案

    //水平方向是否可以被回收掉的阈值
    public float getThreshold(RecyclerView.ViewHolder viewHolder) {
        return mRv.getWidth() * getSwipeThreshold(viewHolder);
    }

因为滑动删除操作是touch事件导致的,且应该是ACTION_UP时,触发的,

所以在ItemTouchHelper 源码里,搜索onTouch字样:

定位到:mOnItemTouchListener,->

继续定位其中的onTouchEvent(),->

case MotionEvent.ACTION_UP:,->

void select(ViewHolder selected, int actionState)->

在这里我注意到有一句代码:animationType = ANIMATION_TYPE_SWIPE_SUCCESS;

这说明删除成功,它的触发条件是:if (swipeDir > 0)->

swipeDir的值: final int swipeDir = prevActionState == ACTION_STATE_DRAG ? 0

: swipeIfNecessary(prevSelected); ->

int swipeIfNecessary(ViewHolder viewHolder)->

 if ((swipeDir = checkHorizontalSwipe(viewHolder, flags)) > 0) {
                return swipeDir;
  }

如此返回1的话,则->checkHorizontalSwipe(viewHolder, flags)->

在其中终于找到源码里阈值的获取之处:

final float threshold = mRecyclerView.getWidth() * mCallback
        .getSwipeThreshold(viewHolder);

于是我就直接复制出来。

总结

代码传送门:喜欢的话,随手点个star。多谢

https://github.com/mcxtzhang/LayoutManagerDemo

本文利用LayoutManager加载显示屏幕上可见的数量的View,搭配ItemTouchHelper处理拖拽&滑动删除逻辑,核心代码不超过50行。且经过封装,四行代码就可以用。

记住LayoutManager,我们写,只layout出界面上可能会看见的那些View即可。

关于ItemTouchHelper,它本身实现了拖拽&滑动删除逻辑,我们只需要在onChildDraw()中绘制动画和onSwiped()中处理数据集(循环or删除)即可。

以后老板让你做这种效果,你只需要:

        mRv.setLayoutManager(new OverLayCardLayoutManager());
        CardConfig.initConfig(this);
        ItemTouchHelper.Callback callback = new RenRenCallback(mRv, mAdapter, mDatas);
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
        itemTouchHelper.attachToRecyclerView(mRv);

如果需要定制特殊的参数,例如显示6层:

         CardConfig.MAX_SHOW_COUNT = 6;

转载请标明出处:

http://blog.csdn.net/zxt0601/article/details/53730908

本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)

代码传送门:喜欢的话,随手点个star。多谢

https://github.com/mcxtzhang/LayoutManagerDemo

时间: 2024-10-25 20:14:56

五行代码实现 炫动滑动 卡片层叠布局,仿探探、人人影视订阅界面 简单&优雅:LayoutManager+ItemTouchHelper的相关文章

jQuery 代码的层定位滑动动画效果

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>jQuery层动画定位滑动</tit

2015祝福在行动:“五行代码”话新年 赛祝福 赢取专属礼品

                                                                                                                                         我的参赛作品详情 -> 1. 活动时间 2014.12.25 - 2014.1.11 23:59 2015.1.15在"高校俱乐部议事大厅"公布获奖名单 2. 参与条件 CSDN高校俱乐部注册在校大学生,还不是

java五行代码导出Excel

目录 先看代码 再看效果 EasyExcel 附: Java按模板导出Excel---基于Aspose实现 Java无模板导出Excel,Apache-POI插件实现 已经写过两种Excel导出插件了.今天再安利一个极简的导出Excel的框架,导出无特殊格式要求的Excel,只需五行代码: 先看代码 再看效果 EasyExcel 本案例用到的框架是阿里推出的EasyExcel,EasyExcel从第一次提交代码(2018年2月)到现在,在GitHub上已经获得6590个Star 以下是官方介绍

Python|基于百度API五行代码实现OCR文字高识别率

朋友扔过来一张图片,说在整理试题答案,但是试题是图片,想从网上搜索答案一个一个敲太累了,能不能将图片里的文字提取出来?我一看这是典型的OCR识别啊,直接祭出神器Tesseract. tesseract -l chi_sim 4.png stdout 目 二 画 口 " 口 出 再对比原图一看哦,不,是不是差的有点儿多?怎么办呢?tesseract识别不利,肯定是咱玩的不溜,为了识别几张图,再进行一通识别训练是不是有点儿浪费时间?现在都2020年了,各大厂商都提供这种文字识别服务,像我知道的百度都

Android--&gt;RecyclerView模仿探探左右滑动布局

站在巨人的肩膀上,才能走得更远. 参考文章:http://blog.csdn.net/zxt0601/article/details/53730908 我在此基础上优化了部分代码, 添加了滑动回调, 可自定义性更强. 并且添加了点击按钮左右滑动的功能. 据说无图都不敢发文章了. 看图: 1:这种功能, 首先需要自己管理布局 继承 RecyclerView.LayoutManager , 显示自己管理布局, 比如最多显示4个view, 并且都是居中显示. 底部的View还需要进行缩放,平移操作.

使用Koloda View在Swift中构建类似Tinder(国内的探探社交应用)的卡片

在过去几年中,随着社交网络应用程序的普及,约会应用程序也迅速出现.其中一个最突出的应用是Tinder.它不仅是一个很棒的约会应用程序,而且还在视图动画或过渡方面创建了新的iOS趋势,例如Tinder Card Swipe或Tinder UI 在这个iOS教程中,我们将学习如何在Swift中构建Tinder Swipe Cards,以便您可以将此功能包含在iOS应用程序中.目前有一些图库支持这种类型的可滑动卡片,其中一个是KolodaView.在本教程中,我们将向您展示如何使用代码示例在Swift

New UI-Java代码动态添加控件或xml布局

New UI-Java代码动态添加控件或xml布局  --转载请注明出处:coder-pig,欢迎转载,请勿用于商业用途! 小猪Android开发交流群已建立,欢迎大家加入,无论是新手,菜鸟,大神都可以,小猪一个人的 力量毕竟是有限的,写出来的东西肯定会有很多纰漏不足,欢迎大家指出,集思广益,让小猪的博文 更加的详尽,帮到更多的人,O(∩_∩)O谢谢! 小猪Android开发交流群:小猪Android开发交流群群号:421858269 新Android UI实例大全目录:http://blog.

iOS炫酷动画图案、多种选择器、网络测速、滑动卡片效果等源码

iOS精选源码 对网络进行测速 自实现大标题,配合原生骨架屏demo 简单方便的pickerVIew记录数据 LZPickerView 科技风绘制组件,简单快速"画"出炫酷图案 ResponderChain+Strategy+MVVM实现一个优雅的TableView Card Slider EWAddressPicker.选择中国省市区的自定制地址选择器 EWDatePicker 日期选择器 EWToast.简易Toast提示框 FMDB改进方案YIIFMDB:直接将Model存入数据

Android使用SVG矢量图打造酷炫动效!

尊重原创,欢迎转载,转载请注明: FROM  GA_studio   http://blog.csdn.net/tianjian4592 一个真正酷炫的动效往往让人虎躯一震,话不多说,咱们先瞅瞅效果: 这个效果我们需要考虑以下几个问题: 1. 这是图片还是文字: 2. 如果是图片该如何拿到图形的边沿线坐标,如果是文字呢? 3. 如果拿到了边沿线坐标,如何让光线沿着路径跑动: 4. 怎么处理过程的衔接: 以上四个问题似乎不是太好处理,而这几个问题也正好是这个效果精华所在,接下来咱们一个一个进行考虑