Android之View篇6————仿陌陌卡片左右滑动选择控件

一.目录

Android之View篇6————仿陌陌卡片左右滑动选择控件

一.目录

二.效果图

三.业务需求梳理

四.思路分析

1. 新建TinderCardView类,并继承FrameLayout

2. 新建TinderStackLayout 类,并继承FrameLayout

五.源码地址

二.效果图

三.业务需求梳理

卡片随着手指的移动进行移动

卡片在移动过程中,随着距离的加大,卡片绕z轴旋转

判断手指的移动方向,显示选择/删除图标,同时图标随距离的增大,透明度增加

手指离开卡片后,根据移动的距离,判断卡片是否移出屏幕,从左边移动还是右边移动

显示的卡片移出完后,增加新的卡片。

显示的4张卡片,需要展示出卡片的层次感

四.思路分析

根据上面的业务逻辑梳理,明显可以知道,实现该功能需要自定义两个View,一个是卡片View(TinderCardView),一个是卡片的容器(TinderStackLayout)。

需求1,2,3都是手指移动过程中发生,即MotionEvent的ACTION_MOVE事件中。

MotionEvent 这一块不知道的可以看我前面写的博客Android之View篇2————View的事件分发

需求4是在手指离开屏幕后中发生的,即MotionEvent的MotionEvent.ACTION_UP事件中

需求5是卡片动画结束后,判断剩余卡片数量,选择是否要加载新的卡片

需求6是加载新卡片时,要求实现的。

1. 新建TinderCardView类,并继承FrameLayout

a.TinderCardView即展示信息的卡片类,重写其onTouch方法

@Override

public boolean onTouch(final View view, MotionEvent motionEvent) {

TinderStackLayout tinderStackLayout = ((TinderStackLayout) view.getParent());

TinderCardView topCard = (TinderCardView) tinderStackLayout.getChildAt(tinderStackLayout.getChildCount() - 1);

if (topCard.equals(view)) {

switch (motionEvent.getAction()) {

case MotionEvent.ACTION_DOWN:

downX = motionEvent.getX();

downY = motionEvent.getY();

view.clearAnimation();

return true;

case MotionEvent.ACTION_MOVE:

newX = motionEvent.getX();

newY = motionEvent.getY();

dX = newX - downX; //手指移动距离

dY = newY - downY;

float posX = view.getX() + dX;

view.setX(view.getX() + dX); //view的新距离 需求1,卡片随手指的移动而移动

view.setY(view.getY() + dY);

float rotation = (CARD_ROTATION_DEGREES * (posX)) / screenWidth;

int halfCardHeight = (view.getHeight() / 2);

if (downY < halfCardHeight - (2 * padding)) {

view.setRotation(rotation); //设置View在Z轴上的旋转角度 需求2,卡片移动过程中,随距离的增大而,选择角度增大

} else {

view.setRotation(-rotation);

}

float alpha = (posX - padding) / (screenWidth * 0.3f);

if (alpha > 0) { //需求3, 判断手指的移动方向,显示选择/删除图标,同时图标随距离的增大,透明度增加

iv_tips.setAlpha(alpha);

iv_tips.setImageResource(R.drawable.ic_like);

} else {

iv_tips.setAlpha(-alpha);

iv_tips.setImageResource(R.drawable.ic_nope);

}

return true;

case MotionEvent.ACTION_UP: //需求4. 手指离开卡片后,根据移动的距离,判断卡片是否移出屏幕,从左边移动还是右边移动

if (isBeyondLeftBoundary(view)) {

removeCard(view, -(screenWidth * 2)); //移动view.向左边移出屏幕

} else if (isBeyondRightBoundary(view)) {

removeCard(view, (screenWidth * 2));

} else {

resetCard(view); //复原view

}

return true;

default:

return super.onTouchEvent(motionEvent);

}

}

return super.onTouchEvent(motionEvent);

}

b.判断是否左右移动距离是否达到要求

private boolean isBeyondLeftBoundary(View view) {

return (view.getX() + (view.getWidth() / 2) < leftBoundary);

}

private boolean isBeyondRightBoundary(View view) {

return (view.getX() + (view.getWidth() / 2) > rightBoundary);

}

c.卡片移出屏幕和复原动画

private void removeCard(final View view, int xPos) { //移出屏幕动画

view.animate()

.x(xPos) //x轴移动距离

.y(0) //y轴移动距离

.setInterpolator(new AccelerateInterpolator()) //插值器 在动画开始的地方速率改变比较慢,然后开始加速

.setDuration(DURATIONTIME) //移动距离

.setListener(new Animator.AnimatorListener() { //监听

@Override

public void onAnimationStart(Animator animator) {

}

@Override

public void onAnimationEnd(Animator animator) {//移出后回调

ViewGroup viewGroup = (ViewGroup) view.getParent();

if (viewGroup != null) {

viewGroup.removeView(view);

int count = viewGroup.getChildCount();

if (count == 1 && listener != null) { //需求5,增加新卡片

listener.onLoad();

}

}

}

@Override

public void onAnimationCancel(Animator animator) {

}

@Override

public void onAnimationRepeat(Animator animator) {

}

});

}

private void resetCard(final View view) { //还原动画

view.animate()

.x(0) //x轴移动

.y(0) //y轴移动

.rotation(0) //循环次数

.setInterpolator(new OvershootInterpolator()) //插值器 向前甩一定值后再回到原来位置

.setDuration(DURATIONTIME);

iv_tips.setAlpha(0f); //图标隐藏

}

2. 新建TinderStackLayout 类,并继承FrameLayout

a.数据的初始化添加

public void setDatas(List list) { //提供给activity调用

this.mList = list;

if (mList == null) {

return;

}

for (int i = index; index < i + STACK_SIZE; index++) {

tc = new TinderCardView(getContext());

tc.bind(mList.get(index));

tc.setOnLoadMoreListener(this);

addCard(tc);

}

}

private void addCard(TinderCardView view) {

int count = getChildCount();

addView(view, 0, params);

float scaleX = 1 - (count / BASESCALE_X_VALUE);

view.animate()

.x(0)

.y(count * scaleY) //需求6,实现层次感

.scaleX(scaleX) //水平缩放比例

.setInterpolator(new AnticipateOvershootInterpolator())

.setDuration(DURATIONTIME);

}

b.实现接口onLoad() 供TinderCardView类调用

@Override

public void onLoad() { //当显示卡片数量==1时,TinderCardView调用该方法添加新卡片

for (int i = index; index < i + (STACK_SIZE - 1); index++) {

if (index == mList.size()) {

return;

}

tc = new TinderCardView(getContext());

tc.bind(mList.get(index));

tc.setOnLoadMoreListener(this);

addCard(tc);

}

int childCount = getChildCount();

for (int i = childCount - 1; i >= 0; i--) {

TinderCardView tinderCardView = (TinderCardView) getChildAt(i);

if (tinderCardView != null) {

float scaleValue = 1 - ((childCount - 1 - i) / 50.0f);

tinderCardView.animate()

.x(0)

.y((childCount - 1 - i) * scaleY)

.scaleX(scaleValue)

.rotation(0)

.setInterpolator(new AnticipateOvershootInterpolator())

.setDuration(DURATIONTIME);

}

}

}

五.源码地址

点位查看源码

android 自定义裁剪 陌陌,Android之View篇6————仿陌陌卡片左右滑动选择布局相关推荐

  1. android 自定义取色器,【Android自定义View】仿Photoshop取色器ColorPicker(二)

    ColorPicker 一款仿Photoshop取色器的Android版取色器. 前言 上一篇已经简单介绍了ColorPicker的项目结构以及两种颜色空间,接下来我们详细解析一下ColorPicke ...

  2. Android 自定义圆形进度条(圆环刻度)View

    转载请注明出处http://blog.csdn.net/shallcheek/article/details/50343677 这个也刚好是公司软件最近的需求需要到的,当初最早的版本是使用美工切好的图 ...

  3. android自定义曲线控件,Android自定义view进阶-- 神奇的贝塞尔曲线

    上一篇介绍了自定义view需要知道的基本函数.新开一篇献给借给我vpn的深圳_奋斗小哥. 转载请注明出处:http://blog.csdn.net/wingichoy/article/details/ ...

  4. Android自定义弹窗模仿微信,Android仿微信右上角点击加号弹出PopupWindow

    本文实例为大家分享了Android仿微信右上角点击加号弹出展示的具体代码,供大家参考,具体内容如下 一.要弹出的布局,随便设计 android:layout_width="match_par ...

  5. android自定义dialog不显示,Android 自定义的dialog显示不正常呢,怎么回事???

    Android 自定义的dialog显示不正常呢,怎么回事??? 用android的自定义布局文件: android:layout_width="match_parent" and ...

  6. Android自定义文件路径箭头,Android自定义ViewGroup实现带箭头的圆角矩形菜单

    本文和大家一起做一个带箭头的圆角矩形菜单,大概长下面这个样子: 要求顶上的箭头要对准菜单锚点,菜单项按压反色,菜单背景色和按压色可配置. 最简单的做法就是让UX给个三角形的图片往上一贴,但是转念一想这 ...

  7. android 自定义相机源码,Android 自定义相机及分析源码

    Android 自定义相机及分析源码 使用Android 系统相机的方法: 要想让应用有相机的action,咱们就必须在清单文件中做一些声明,好让系统知道,如下 action的作用就是声明action ...

  8. android 自定义透明 等待 dialog,Android自定义Dialog内部透明、外部遮罩效果

    Android自定义Dialog内部透明.外部遮罩效果 发布时间:2020-09-09 03:01:41 来源:脚本之家 阅读:117 作者:zst1303939801 本文实例为大家分享了Andro ...

  9. android 自定义进度条 水量,Android自定义带水滴的进度条样式(带渐变色效果)...

    一.直接看效果 二.直接上代码 1.自定义控件部分 package com.susan.project.myapplication; import android.app.Activity; impo ...

最新文章

  1. 谷歌放弃python-老大离开Google,去了Dropbox
  2. Reddit高赞:机器学习领域「八宗罪」!同行评审变味,盲目崇拜盛行
  3. 页面布局_word页面布局
  4. 后宫宛如传服务器维护,合服丨《后宫宛如传》合服公告
  5. [SDOI2005]动物园 匹配
  6. Linux调度器 - deadline调度器
  7. JavaWeb19-HTML篇笔记
  8. 【POJ】【2125】Destroying the Graph
  9. 小猿圈之Python开发的技巧一?
  10. 计算机刊物SCI影响因子排名
  11. 根据项目或WBS结算规则批量生成下阶WBS的结算规则-CJB2
  12. 针对Google注册不能收到手机验证码的解决方案
  13. 他励直流电动机的机械特性
  14. 苹果手机怎么设置时间24小时制_手机资讯:无法激活 iMessage 等问题及解决办法汇总...
  15. App关键字(100字符)优化的方法
  16. 美本计算机专业,2018美国本科计算机cs专业排名|美国本科cs专业排名
  17. 计算机毕设推荐基于微信小程序的自来水收费系统
  18. 2012-11-09《Oopsnbsp;Inbsp;Did…
  19. 电影之记忆2:(杀手代号47)
  20. 轻松通关以太坊--初识以太坊

热门文章

  1. 计算机辅助制造在计算机应用,计算机辅助制造
  2. 表观遗传研究丨Atlas Antibodies 抗组蛋白抗体
  3. Ubuntu桌面卡顿、不流畅、反应慢解决
  4. 【C++】1045:收集瓶盖赢大奖(信息学奥赛)
  5. java 接口开发时间_这35个接口,用Java开发,一般要多少天?一天可以完成多少个...
  6. 恰好装满背包、恰好取k倍(取余)
  7. 分类评估标准混淆矩阵(图像分类篇)
  8. 使用BeautifulSoup模块获取糗事百科上的笑话
  9. 解决win7 开机时联网很慢,网络连接一直转圈问题
  10. [日推荐]『吸猫君』冬日取暖吸猫大法 好!