探探的滑动选择妹子的功能,算是一个很经典的交互方式。自从出来以后可以说是备受关注,渐渐地很多类似功能的app也都有尝试。实现也是具有综合性的挑战,所以说网上也是有不少例子的,在这里我通过自定义ViewGroup的方式来实现。
需要达到的效果
实现的过程中,当然我们需要参考探探。这里实现最核心的功能,如下:
卡片的层叠显示
拖动选择卡片
加载数据
怎么实现呢?
当第一眼看到,察觉到的难点当然是拖动的实现。拖动的过程中会旋转,同时层叠中的view 会改变位置。如果松手还会返回原位置或者移除卡片。在自定义viewGroup中拖动事件算是很麻烦的实现。但是呢官方给我们提供一一大神器ViewDragHelper。有了它我们实现起来就事半功倍了,在这里之前也有文章介绍。如果不太明白使用,参考资料会列出来。既然拖动现在好说了。那么层叠的效果呢?这里不得不说算是核心了。在这里我也走过弯路,因为之前的实现我是想的让onlayout的时候,让子view在不同位置,并且缩放的宽高也用onLayout变更left,top,right,bottom实现。但是实践过程中会变得很复杂,不好实现。后面果断改变思路。在onLayout中对每一个view都根据它自身的已测量宽高居中显示,然后通过设置setScale,setTranslationY改变y轴防线的偏移量实现。可以看到我们是居中layout,我们事先的效果是y轴方向的偏移,所以主要看y轴的layout.这里需要琢磨一下滑动的过程中的显示,卡片的总量是固定值,我们默认设置为4,当然是可以改变的。我们可以看到探探滑动的时候,最底层的view,跟倒数第二层初始状态是叠在一起的。我们定义从最顶层为第一层,一次递增。并且每一层都有一个固定的offset,每一层都有固定的缩放scale。因为缩放也会造成y轴方向的偏移变化,这里记缩放引起的偏移scaleYOffset.所以总的totalOffset = offset + scaleYOffset.可以看到offset,scaleYOffset都跟子view所在的层次有关。接下来结合代码分析
先定义一些常量
private static final float DEFAULT_SCALE = 0.05f;//默认缩放的级别
private static final int DEFAULT_OFFSET = 10;//dp
private static final int DEFAULT_MARGIN = 10;//dp
private static final int DEFAULT_DEGRESS = 20;//旋转的度数
private static final int DEFAULT_SHOW_COUNT = 4;//默认显示数量
layout 实现
protected void onLayout(boolean changed, int l, int t, int r, int b) {
float scale = 1f;
int level = 0;
for (int i = getChildCount() - 1; i >= 0; i--) {
View child = getChildAt(i);
float scaleValue = scale - DEFAULT_SCALE * (level);
int offset = ViewExKt.dp2px(this, DEFAULT_OFFSET);
int offsetValue = offset * (level);
child.layout(mCenterX - child.getMeasuredWidth() / 2
, mCenterY - child.getMeasuredHeight() / 2