android 通过贝塞尔曲线 实现爱心点赞功能
android 通过贝塞尔曲线 实现爱心点赞功能:ValueAnimatior:核心功能:已知起点p0, 终p3,中间点 p1、p2 工具贝塞尔公司 计算路径中各个点案例1: 重力抛物线案例2: 目前的核心代码:LoveLayoutpackage mk.denganzhi.com.zhiwenku;import java.util.Random;i...
·
android 通过贝塞尔曲线 实现爱心点赞功能:
ValueAnimatior:
核心功能:
已知起点p0, 终p3,中间点 p1、p2 通过贝塞尔曲线 计算路径中各个点
案例1: 重力抛物线
案例2: 爱心点赞功能
核心代码:LoveLayout
package mk.denganzhi.com.zhiwenku;
import java.util.Random;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import mk.denganzhi.com.zhiwenku.BezierEvaluator;
import mk.denganzhi.com.zhiwenku.R;
public class LoveLayout extends RelativeLayout {
Drawable[] drawables = new Drawable[3];
private Random random = new Random();
private int dHeight;
private int dWidth;
private LayoutParams params;
private int mWidth;
private int mHeight;
public LoveLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public LoveLayout(Context context) {
super(context);
init();
}
public LoveLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 必须在测量完毕以后才知道控件高度、和宽度
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
}
private void init() {
//准备图片集合
drawables[0] = getResources().getDrawable(R.drawable.red);
drawables[1] = getResources().getDrawable(R.drawable.yellow);
drawables[2] = getResources().getDrawable(R.drawable.blue);
//得到图片的原始高度
dWidth = drawables[0].getIntrinsicWidth();
dHeight = drawables[0].getIntrinsicHeight();
params = new LayoutParams(dWidth, dHeight);
//将iv添加到父容器底部、水平居中位置
params.addRule(CENTER_HORIZONTAL);
params.addRule(ALIGN_PARENT_BOTTOM);
}
// 1. 第一步: 绘制ImageView 心形
public void addLoveIcon(){
//添加心形,并开始执行动画
final ImageView iv = new ImageView(getContext());
iv.setImageDrawable(drawables[random.nextInt(3)]);
//将iv添加到父容器底部、水平居中位置
iv.setLayoutParams(params);
addView(iv);
//开始属性动画:平移、透明度渐变、缩放动画
AnimatorSet set = getAnimator(iv);
//监听动画执行完毕,将iv移除或者复用
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
removeView(iv);
}
});
set.start();
}
// 得到一个iv的动画集合
private AnimatorSet getAnimator(ImageView iv) {
//平移、透明度渐变、缩放动画
//1.alpha动画
ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 0.3f,1f);
//2.缩放动画
ObjectAnimator scaleX = ObjectAnimator.ofFloat(iv, "scaleX", 0.3f,1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(iv, "scaleY", 0.3f,1f);
//三个动画同时执行
AnimatorSet enter = new AnimatorSet();
enter.setDuration(600);
enter.playTogether(alpha,scaleX,scaleY);
// enter.setTarget(iv);
//设置平移的曲线动画---贝塞尔曲线
// 2. 第二步启动估值器
ValueAnimator bezierAnimator = getBezierValueAnimator(iv);
AnimatorSet set = new AnimatorSet();
//同时依次执行 实现属性动画
set.playSequentially(enter,bezierAnimator);
set.setTarget(iv);
return set;
}
//得到一个贝塞尔曲线动画
private ValueAnimator getBezierValueAnimator(final ImageView iv) {
//根据贝塞尔公式确定四个点(起始点p0,拐点1p1,拐点2p2,终点p3)
PointF pointF0 = new PointF((mWidth-dWidth)/2, mHeight-dHeight);
PointF pointF3 = new PointF(random.nextInt(mWidth), 0);
PointF pointF1 = getPointF(1);
PointF pointF2 = getPointF(2);
BezierEvaluator evaluator = new BezierEvaluator(pointF1,pointF2);
ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointF0,pointF3);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
// iv.setX(pointF.x);
// iv.setY(pointF.y);
iv.setX(pointF.x);
iv.setY(pointF.y);
Log.e("denganzhi1","坐标是:x"+ pointF.x +" y:" + pointF.y);
iv.setAlpha(1-animation.getAnimatedFraction());//1~0 百分比
}
});
animator.setDuration(10000);
return animator;
}
private PointF getPointF(int i) {
PointF pointF = new PointF();
pointF.x = random.nextInt(mWidth);
if(i==1){
pointF.y = random.nextInt(mHeight/2)+mHeight/2;
}else{
pointF.y = random.nextInt(mHeight/2);
}
return pointF;
}
}
估值器:BezierEvaluator
package mk.denganzhi.com.zhiwenku;
import android.animation.TypeEvaluator;
import android.graphics.PointF;
public class BezierEvaluator implements TypeEvaluator<PointF> {
private PointF pointF1;
private PointF pointF2;
public BezierEvaluator(PointF pointF1, PointF pointF2) {
// TODO Auto-generated constructor stub
this.pointF1 = pointF1;
this.pointF2 = pointF2;
}
@Override
public PointF evaluate(float t, PointF point0, PointF point3) {
// b(t)=p0*(1-t)*(1-t)*(1-t)+3*p1*t*(1-t)*(1-t)+3*p2*t*t*(1-t)+p3*t*t*t
PointF point = new PointF();
point.x = point0.x*(1-t)*(1-t)*(1-t)
+3*pointF1.x*t*(1-t)*(1-t)
+3*pointF2.x*t*t*(1-t)
+point3.x*t*t*t;
point.y = point0.y*(1-t)*(1-t)*(1-t)
+3*pointF1.y*t*(1-t)*(1-t)
+3*pointF2.y*t*t*(1-t)
+point3.y*t*t*t;
return point;
}
}
MainActivity代码,使用控件:
package mk.denganzhi.com.zhiwenku;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private LoveLayout loveLayout;
MyBazierLayout myBazierLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loveLayout = (LoveLayout)findViewById(R.id.loveLayout);
myBazierLayout = findViewById(R.id.loveLayout2);
}
public void start(View view){
loveLayout.addLoveIcon();
// myBazierLayout.addLoveIcon();
}
public void translate(View view) {
// myBazierLayout.translateFun();
}
}
MainActivity 的xml布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<mk.denganzhi.com.zhiwenku.LoveLayout
android:id="@+id/loveLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<mk.denganzhi.com.zhiwenku.MyBazierLayout
android:id="@+id/loveLayout2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone">
</mk.denganzhi.com.zhiwenku.MyBazierLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="start"
android:text="赞一个" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="translate"
android:text="移动" />
</LinearLayout>
</RelativeLayout>
效果图功能:
源码地址:https://download.csdn.net/download/dreams_deng/12255079
参考:https://www.jb51.net/article/137316.htm
ValueAnimator.ofObject的使用: https://blog.csdn.net/zhaihaohao1/article/details/80941009
归纳:使用贝塞尔公式绘制曲线路径
package mk.denganzhi.com.zhiwenku;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
public class TestActivity extends AppCompatActivity {
ImageButton mybtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mybtn = (ImageButton) findViewById(R.id.mybtn);
}
boolean isFlag=false;
public void startAnimation(View view) {
WindowManager wm = (WindowManager) this
.getSystemService(Context.WINDOW_SERVICE);
final int width = wm.getDefaultDisplay().getWidth();
int height = wm.getDefaultDisplay().getHeight();
float startX= mybtn.getLeft();
float startY =mybtn.getTop();
PointF pointF0 = new PointF(startX, startY);
PointF pointF2 = new PointF(startX-50,startY-10);
PointF pointF3 = new PointF(startX-300,startY-500);
// 贝塞尔公式
PointF pointF4 = new PointF(width/2-mybtn.getWidth()/2,height/2-mybtn.getHeight()/2);
BezierEvaluator evaluator = new BezierEvaluator(pointF2,pointF3);
Log.e("denganzhi","startx:"+startX+" startY:"+startY);
ValueAnimator animator = ValueAnimator.ofObject(evaluator, pointF0,pointF4);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
// iv.setX(pointF.x);
// iv.setY(pointF.y);
int scaleBeiShu= (width)/mybtn.getWidth();
mybtn.setX(pointF.x);
mybtn.setY(pointF.y);
Log.e("denganzhi1","坐标是:x"+ pointF.x +" y:" + pointF.y +" scaleBeiShu:"+scaleBeiShu);
if(pointF.x<350){
if(!isFlag){
mybtn.setImageDrawable(new BitmapDrawable());
/**
* .scaleY(2) : 放大到2倍
* scaleYBy(1): 在原来基础上放大1倍,累加过程
*
* scrollTo
* scrollBy
*/
mybtn.animate()
.scaleYBy(1)
.scaleXBy(scaleBeiShu)
.setDuration(3000);
isFlag=true;
}
}
// mybtn.setAlpha(1-animation.getAnimatedFraction());//1~0 百分比
}
});
animator.setDuration(1000);
animator.start();
}
}
activity_test 布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mk.denganzhi.com.zhiwenku.TestActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#bfa"
android:layout_centerVertical="true"></LinearLayout>
<ImageButton
android:id="@+id/mybtn"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@mipmap/ic_launcher"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="30dp"
android:layout_marginRight="30dp"
android:background="#00f"
android:onClick="startAnimation"
/>
</RelativeLayout>
效果:
直接起点,终点, 中间2个点就可以使用贝塞尔曲线,绘制绘制轨迹
问题就是:不知道它的点,知道点以后才知道轨迹
更多推荐
已为社区贡献6条内容
所有评论(0)