转载请注意:http://blog.csdn.net/wjzj000/article/details/73441173

本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅…
https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入)
https://github.com/zhiaixinyang/MyFirstApp(Retrofit+RxJava+MVP)

写在前面

本来想昨天就把这个效果分析完毕。然后事与愿违,随便玩了玩时间就没了。没办法只有今天补上….最难逃儿女情长书接上回楚霸王,让我们续上仿天天美剧拖动卡片的效果(上):
http://blog.csdn.net/wjzj000/article/details/73432852

开始

我们上部分分析完了setAdapter的一系列的过程,这部分我们要通过FlingCardListener来近距离的看一看我们拖动Card的实现效果。


在开始FlingCardListener之前,让我们回过来上看一个类LinearRegression。可能各位看官已经把这个类给忘了,所以我们在分析的一开始就看一看它。

LinearRegression


public LinearRegression(float[] x, float[] y) {
if (x.length != y.length) {
throw new IllegalArgumentException("array lengths are not equal");
}
N = x.length;

//求平均值
double sumx = 0.0, sumy = 0.0, sumx2 = 0.0;
for (int i = 0; i < N; i++) sumx += x[i];
for (int i = 0; i < N; i++) sumx2 += x[i]*x[i];
for (int i = 0; i < N; i++) sumy += y[i];
double xbar = sumx / N;
double ybar = sumy / N;

//求方差
double xxbar = 0.0, yybar = 0.0, xybar = 0.0;
for (int i = 0; i < N; i++) {
xxbar += (x[i] - xbar) * (x[i] - xbar);
yybar += (y[i] - ybar) * (y[i] - ybar);
xybar += (x[i] - xbar) * (y[i] - ybar);
}
beta = xybar / xxbar;
alpha = ybar - beta * xbar;

//一些计算公式
double rss = 0.0;
double ssr = 0.0;
for (int i = 0; i < N; i++) {
double fit = beta*x[i] + alpha;
rss += (fit - y[i]) * (fit - y[i]);
ssr += (fit - ybar) * (fit - ybar);
}

int degreesOfFreedom = N-2;
R2 = ssr / yybar;
svar = rss / degreesOfFreedom;
svar1 = svar / xxbar;
svar0 = svar/N + xbar*xbar*svar1;
}

FlingCardListener

这里比较重要的方法是onTouch()方法,构造方法传参非常多,各个变量的使用将逐一在onTouch()方法这种展开。因此接下来让我们看一看onTouch()方法。


@Override
public boolean onTouch(View view, MotionEvent event) {

switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
//确定唯一的坐标点,避免多指操作带来的问题
mActivePointerId = event.getPointerId(0);
float x = 0;
float y = 0;
boolean success = false;
try {
x = event.getX(mActivePointerId);
y = event.getY(mActivePointerId);
success = true;
} catch (IllegalArgumentException e) {
Log.w(TAG, "Exception in onTouch(view, event) : " + mActivePointerId, e);
}
if (success) {
//记住我们按下时的坐标
aDownTouchX = x;
aDownTouchY = y;
//设置View的初始坐标是传入frame的X、Y值
if (aPosX == 0) {
aPosX = frame.getX();
}
if (aPosY == 0) {
aPosY = frame.getY();
}
//记录按压位置状态
if (y < objectH / 2) {
touchPosition = TOUCH_ABOVE;
} else {
touchPosition = TOUCH_BELOW;
}
}

view.getParent().requestDisallowInterceptTouchEvent(true);
break;

case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
//将在下文展开
resetCardViewOnStack();
view.getParent().requestDisallowInterceptTouchEvent(false);
break;

case MotionEvent.ACTION_MOVE:
final int pointerIndexMove = event.findPointerIndex(mActivePointerId);
final float xMove = event.getX(pointerIndexMove);
final float yMove = event.getY(pointerIndexMove);

final float dx = xMove - aDownTouchX;
final float dy = yMove - aDownTouchY;

aPosX += dx;
aPosY += dy;
/**
* objectX= frame.getX()
* 此处为计算移动距离
*/

float distobjectX = aPosX - objectX;
/**
* 如果我们仔细看Card的拖动效果可以发现,
* 有一个小小的旋转效果如果我们仔细看Card的拖动效果可以发现,有一个小小的旋转效果
*
* 此处是计算旋转角度自定义的公式,当拖动X轴距离和parentWidth相等时,
* 那么最大旋转的效果就是:BASE_ROTATION_DEGREES * 2.f
*/

float rotation = BASE_ROTATION_DEGREES * 2.f * distobjectX / parentWidth;
if (touchPosition == TOUCH_BELOW) {
rotation = -rotation;
}

//设置Card的位置,旋转等
frame.setX(aPosX);
frame.setY(aPosY);
frame.setRotation(rotation);
//onScroll方法调用
mFlingListener.onScroll(getScrollProgressPercent());
break;
}

return true;
}

这里的思路是通过setListener的时候,new FlingCardListener把每一个Card的View对象和Adapter中对应的数据,FlingCardListener将通过onTouch()方法中的坐标变换进行对Card
位置进行设置,并且完成回调。


resetCardViewOnStack()


private boolean resetCardViewOnStack() {
//如果超出左边界限
if (movedBeyondLeftBorder()) {
// 执行左划出效果,相关执行代码在这个方法中( onSelected()在下文展开 )
// getExitPoint()得到离开时的坐标Y的方法
onSelected(true, getExitPoint(-objectW), 100);
mFlingListener.onScroll(-1.0f);
} else if (movedBeyondRightBorder()) {
// 执行右划出效果
onSelected(false, getExitPoint(parentWidth), 100);
mFlingListener.onScroll(1.0f);
} else {
//如果不从左或右划出,那么便是Card回弹
float abslMoveDistance = Math.abs(aPosX - objectX);
aPosX = 0;
aPosY = 0;
aDownTouchX = 0;
aDownTouchY = 0;
frame.animate()
.setDuration(200)
.setInterpolator(new OvershootInterpolator(1.5f))
.x(objectX)
.y(objectY)
.rotation(0);
mFlingListener.onScroll(0.0f);
if (abslMoveDistance < 4.0) {
mFlingListener.onClick(dataObject);
}
}
return false;
}

onSelected()

Card划出的代码实现,需要接受exitY,离开的坐标Y


public void onSelected(final boolean isLeft,float exitY, long duration) {
isAnimationRunning = true;
float exitX;
if (isLeft) {
/**
* 计算离开点的X坐标(左移动为减,右移动为加)
* getRotationWidthOffset():
* objectW / MAX_COS - objectW(计算旋转的宽度偏移量)
* MAX_COS=cos45
*/

exitX = -objectW - getRotationWidthOffset();
} else {
exitX = parentWidth + getRotationWidthOffset();
}

//弹出Card的代码实现
this.frame.animate()
.setDuration(duration)
.setInterpolator(new AccelerateInterpolator())
.x(exitX)
.y(exitY)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (isLeft) {
//左边移出回调
mFlingListener.onCardExited();
mFlingListener.leftExit(dataObject);
} else {
//右边移出回调
mFlingListener.onCardExited();
mFlingListener.rightExit(dataObject);
}
isAnimationRunning = false;
}
})
.rotation(getExitRotation(isLeft));
}

getExitPoint()

得到离开时的坐标Y的方法


private float getExitPoint(int exitXPoint) {
float[] x = new float[2];
x[0] = objectX;
x[1] = aPosX;

float[] y = new float[2];
y[0] = objectY;
y[1] = aPosY;

LinearRegression regression = new LinearRegression(x, y);

//这个返回值是一个线性方程: y = ax+b
return (float) regression.slope() * exitXPoint + (float) regression.intercept();
}

梳理

走到这里,整体的流程其实还是比较明确的:我们折叠的多个Card的效果是通过类似ListView的实现就行完成的。每一个Card的View在通过设置Listener进行完成Card的左右拖动的效果。而实现弹动的效果是用属性动画完成的。


尾声

希望各位看官可以star我的GitHub,三叩九拜,满地打滚求star:

https://github.com/zhiaixinyang/PersonalCollect
https://github.com/zhiaixinyang/MyFirstApp

更多相关文章

  1. 有关WebView的一些使用方法
  2. Android 修改spinner 字体颜色 样式的方法
  3. Android 软键盘弹出时把原来布局顶上去的解决方法
  4. Android多窗口分屏(原生方法)
  5. getCacheDir()和getFilesDir()方法区别
  6. Object 开发中常用的重写方法总结toString,equals,hashCode,compare
  7. java 构造器内部的多态方法和行为
  8. Javassist生成class(生成类,方法,字段,注解)
  9. Eclipse创建的包变成文件夹的解决方法

随机推荐

  1. Android 隐藏StatusBar
  2. Android界面布局开发使用的标签介绍
  3. 活动的启动模式汇总
  4. android ScrollView边界阴影方法
  5. android全屏设置代码:
  6. ListView 常用属性 详解
  7. Android UI设计随笔
  8. Android的status bar分析
  9. Android四大组件之 BroadcastReceiver
  10. android开发必看资源URL