Java 如何实现这种自定义视图波浪动画? 我试图在波的中间用圆圈来实现这个定制波动画。
下面是我的自定义视图。它运行在一个不同的方向上,并且在波的中间有一条线,导致一个坏的UX。< /P> 我试图按照一些相关的教程,但我不能得到相同的动画。 如果有任何库o代码样本可以遵循它可以帮助我很多 谢谢Java 如何实现这种自定义视图波浪动画? 我试图在波的中间用圆圈来实现这个定制波动画。,java,android,android-layout,android-animation,android-custom-view,Java,Android,Android Layout,Android Animation,Android Custom View,下面是我的自定义视图。它运行在一个不同的方向上,并且在波的中间有一条线,导致一个坏的UX。< /P> 我试图按照一些相关的教程,但我不能得到相同的动画。 如果有任何库o代码样本可以遵循它可以帮助我很多 谢谢 import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; imp
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import com.guille.stressmeterapp.R;
import org.jetbrains.annotations.Nullable;
public class WaveCustomView extends View {
private int mWidth = 0;
private int mHeight = 0;
private Path path;
private Paint paint;
private int waveHeight = 300;
private int waveWidth = 600;
private int originalY = 750;
private Region region;
private int dx = 0;
private Bitmap mBitmap;
private int animationDuration = 3000;
public WaveCustomView(Context context) {
super(context, null);
initUi();
}
public WaveCustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs, 0);
initUi();
}
public WaveCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initUi();
}
private void initUi() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.parseColor("#000000"));
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(15);
path = new Path();
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.circle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
int desired = (int) (getPaddingLeft() + getPaddingRight());
width = desired;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
int desired = (int) (getPaddingTop() + getPaddingBottom());
height = desired;
}
mWidth = width;
mHeight = height;
waveWidth = mWidth / 2;
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(path, paint);
setDrawData();
Rect bounds = region.getBounds();
if (bounds.top < originalY) {
canvas.drawBitmap(mBitmap, bounds.right - (mBitmap.getWidth() >> 1), bounds.top - (mBitmap.getHeight() >> 1), paint);
} else {
canvas.drawBitmap(mBitmap, bounds.right - (mBitmap.getWidth() >> 1), bounds.bottom - (mBitmap.getHeight() >> 1), paint);
}
}
private void setDrawData() {
path.reset();
int halfWaveWidth = waveWidth / 2;
path.moveTo(-waveWidth + dx, originalY);
for (int i = -waveWidth; i < mWidth + waveWidth; i = i + waveWidth) {
path.rQuadTo(halfWaveWidth >> 1, -waveHeight, halfWaveWidth, 0);
path.rQuadTo(halfWaveWidth >> 1, waveHeight, halfWaveWidth, 0);
}
region = new Region();
Region clip = new Region((int) (mWidth / 2 - 0.1), 0, mWidth / 2, mHeight * 2);
region.setPath(path, clip);
path.close();
}
public void startAnimate() {
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float factor = (float) valueAnimator.getAnimatedValue();
dx = (int) ((waveWidth) * factor);
invalidate();
}
});
animator.setDuration(animationDuration);
animator.start();
}
导入android.animation.ValueAnimator;
导入android.content.Context;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Paint;
导入android.graphics.Path;
导入android.graphics.Rect;
导入android.graphics.Region;
导入android.util.AttributeSet;
导入android.view.view;
导入android.view.animation.LinearInterpolator;
导入com.guille.stressmeterapp.R;
导入org.jetbrains.annotations.Nullable;
公共类WaveCustomView扩展了视图{
私有int mWidth=0;
私有整数mHheight=0;
专用路径;
私人油漆;
专用int波高=300;
专用int波宽=600;
私有整数初始值=750;
私人区域;
私有整数dx=0;
私有位图mBitmap;
私有int animationDuration=3000;
公共WaveCustomView(上下文){
super(上下文,null);
initUi();
}
public WaveCustomView(上下文上下文,@Nullable AttributeSet attrs){
超级(上下文,属性,0);
initUi();
}
public WaveCustomView(上下文上下文,@Nullable AttributeSet attrs,int-defStyleAttr){
super(上下文、attrs、defStyleAttr);
initUi();
}
私有void initUi(){
油漆=新油漆();
paint.setAntiAlias(真);
paint.setColor(Color.parseColor(#000000”);
绘制.设置样式(绘制.样式.笔划);
油漆。设置行程宽度(15);
路径=新路径();
mBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.circle);
}
@凌驾
测量时的保护空隙(内部宽度测量等级、内部高度测量等级){
超级测量(宽度测量、高度测量);
int widthMode=MeasureSpec.getMode(widthmasurespec);
int widthSize=MeasureSpec.getSize(widthMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
int heightSize=MeasureSpec.getSize(heightMeasureSpec);
整数宽度;
内部高度;
if(widthMode==MeasureSpec.justice){
宽度=宽度大小;
}否则{
所需的int=(int)(getPaddingLeft()+getPaddingRight());
宽度=所需宽度;
}
if(heightMode==MeasureSpec.justice){
高度=高度大小;
}否则{
所需的int=(int)(getPaddingTop()+getPaddingBottom());
高度=所需高度;
}
mWidth=宽度;
mHeight=高度;
波宽=mWidth/2;
设置测量尺寸(宽度、高度);
}
@凌驾
受保护的void onDraw(画布){
super.onDraw(帆布);
画布.绘制路径(路径,绘制);
setDrawData();
Rect bounds=region.getBounds();
if(bounds.top>1)、bounds.top-(mBitmap.getHeight()>>1)、paint);
}否则{
drawBitmap(mBitmap,bounds.right-(mBitmap.getWidth()>>1)、bounds.bottom-(mBitmap.getHeight()>>1)、paint);
}
}
私有void setDrawData(){
path.reset();
int halfWaveWidth=波宽/2;
路径移动到(-waveWidth+dx,原始);
对于(int i=-waveWidth;i>1,-波高,半波宽,0);
路径rQuadTo(半波宽>>1,波高,半波宽,0);
}
区域=新区域();
区域剪辑=新区域((int)(mWidth/2-0.1),0,mWidth/2,mHeight*2);
region.setPath(路径,剪辑);
path.close();
}
公共无效startAnimate(){
ValueAnimator animator=ValueAnimator.offload(0,1);
setRepeatCount(ValueAnimator.INFINITE);
setInterpolator(新的LinearInterpolator());
animator.addUpdateListener(新值animator.AnimatorUpdateListener(){
@凌驾
动画更新上的公共无效(ValueAnimator ValueAnimator){
float factor=(float)valueAnimator.getAnimatedValue();
dx=(int)((波宽)*系数);
使无效();
}
});
animator.setDuration(animationDuration);
animator.start();
}
您的代码看起来不错。只需从setDrawData
方法中删除这一行即可
path.close();
此行关闭路径。这意味着它将路径BGGNIGIG与路径结束连接起来。这就是为什么在波的中间看到行的原因。 以下是没有中间线的结果:
如果要更改动画方向,只需更改dx
变量的符号即可。更改此项:
dx = (int) ((waveWidth) * factor);
为此:
dx = - (int) (waveWidth * factor);
或者代替这个:
path.moveTo(-waveWidth + dx, originalY);
这样做:
path.moveTo(-waveWidth - dx, originalY);
最终结果:
不清楚您想要哪种类型的动画。感谢您的反馈,问题现已更新,希望这能有所帮助。