首先说一下简单的实现思路:
1)线会跳动,所以我们首先想到的是动画。
2)因为跳动的线是一根曲线,所以想到的是贝赛尔曲线。
3)使用安卓ValueAnimation获取贝塞尔曲线的中间点的坐标,来实现曲线变形,达到弯曲还原,类似跳动的现象。
4)曲线跳动和安卓5.0新特性相结合,所以需要引入包:
compile 'com.android.support:design:25.3.0'
下面是这个跳动曲线的具体实现:
1)在清单文件里面配置
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登录"
android:textSize="28sp"
android:layout_marginTop="20dp"
android:layout_gravity="center"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputLayout
android:id="@+id/login_username_tl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="60dp">
<android.support.design.widget.TextInputEditText
android:id="@+id/et_username"
android:background="@null"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLength="11"
android:lines="1"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:inputType="phone"/>
</android.support.design.widget.TextInputLayout>
<com.yinfork.linedlayout.JumpLineView
android:id="@+id/jumbLine1"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_below="@+id/login_username_tl"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"/>
<ImageView
android:id="@+id/username_clear_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_alignRight="@+id/jumbLine1"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_above="@+id/jumbLine1"
android:background="@drawable/x_mark_white"
android:visibility="gone"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputLayout
android:id="@+id/login_passward_tl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="60dp">
<android.support.design.widget.TextInputEditText
android:id="@+id/et_pwd"
android:background="@null"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:maxLength="20"
android:lines="1"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:inputType="numberPassword"/>
</android.support.design.widget.TextInputLayout>
<com.yinfork.linedlayout.JumpLineView
android:id="@+id/jumbLine2"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_below="@+id/login_passward_tl"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"/>
<ImageView
android:id="@+id/password_clear_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_above="@+id/jumbLine2"
android:layout_alignRight="@+id/login_passward_tl"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:background="@drawable/x_mark_white"
android:visibility="gone"/>
</RelativeLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="ok"
android:text="向上跳"
android:layout_margin="10dp"/>
<Button
android:text="向下跳"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="start"
android:layout_margin="10dp"/>
</LinearLayout>
3)跳动线的具体实现如下:
package com.nuoyuan.sp2p.widget;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.LinearInterpolator;
/**
* Created by Tom on 2017/3/21.
*/
public class JumpLineView extends View {
private static final String TAG = JumpLineView.class.getSimpleName();
private Path mPath;
private Paint mPaint;
private int numb = 0;
private Point endPoint;
private Point startPoint;
private Point assistPoint; // 辅助点
private boolean isJump = true;
private ValueAnimator valueAnimator;
private static final int POINTWIDTH = 5; //画笔的宽度
public JumpLineView(Context context) {
this(context, null);
}
public JumpLineView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public JumpLineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* 初始化
*/
private void init() {
mPaint = new Paint(); //画笔
mPath = new Path(); //线段
// 抗锯齿
mPaint.setAntiAlias(true);
// 防抖动
mPaint.setDither(true);
// 画笔颜色
mPaint.setColor(Color.GRAY);
// 笔宽
mPaint.setStrokeWidth(POINTWIDTH);
// 空心
mPaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* 获取二介贝塞尔曲线的之间点的Y轴变化率
*/
if(valueAnimator != null){
numb = (int) valueAnimator.getAnimatedValue();
}else{
initAnimation();
}
Log.e(">>>>>>>>>>","numb:"+numb);
if(!valueAnimator.isRunning()){ //如果动画停止,贝塞尔曲线点回归原位
numb = 0;
}
/**
* 动态的绘制贝塞尔曲线
*/
startPoint = new Point(0,getHeight()/4);
endPoint = new Point(getWidth(), getHeight()/4);
assistPoint = new Point(getWidth()/2, getHeight()/8+10+numb);
// 重置路径
mPath.reset();
//一根直线
mPath.moveTo(startPoint.x, startPoint.y);
//贝塞尔曲线
mPath.quadTo(assistPoint.x, assistPoint.y, endPoint.x, endPoint.y);
//画线
canvas.drawPath(mPath, mPaint);
if (valueAnimator != null && valueAnimator.isRunning()) {
invalidate();
}
}
private void initAnimation(){
if(isJump){
valueAnimator = getJumpValueAnimator();
}else{
valueAnimator = getSinkValueAnimator();
}
}
/**
*开始动画
*/
public void startAnimation() {
valueAnimator.start();
invalidate();//刷新布局
}
/**
* 动画向下跳的动画
*/
public void getSinkAnimator(){
this.isJump = false;
}
/**
* 动画向上执行
*/
public void getJumpAnimator(){
this.isJump = true;
}
/**
* 设置线的颜色
*/
public void setLineColor(int color){
mPaint.setColor(color);
invalidate();
}
/**
* 创建从下往上弹的动画
* @return
*/
private ValueAnimator getJumpValueAnimator() {
ValueAnimator valueAnimator = ValueAnimator.ofInt(50,-10);
valueAnimator.setDuration(300);
valueAnimator.setRepeatCount(0);//Animation.INFINITE 表示重复多次
valueAnimator.setRepeatMode(ValueAnimator.RESTART);//RESTART表示从头开f始,REVERSE表示从末尾倒播
valueAnimator.setInterpolator(new AnticipateOvershootInterpolator(2.5f));
return valueAnimator;
}
/**
* 创建从上往下弹的动画
*/
private ValueAnimator getSinkValueAnimator(){
ValueAnimator valueAnimator = ValueAnimator.ofInt(-50,30);
valueAnimator.setRepeatCount(0);
valueAnimator.setDuration(300);
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.setInterpolator(new LinearInterpolator());
return valueAnimator;
}
}