一个动态波浪纹Android界面
IndexActivity.java
package com.example.rubikrobot; import androidx.appcompat.app.AppCompatActivity; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.View; import android.view.Window; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.Button; import android.widget.ImageView; import java.util.ArrayList; public class IndexActivity extends AppCompatActivity { private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_index); final RippleBackground rippleBackground=findViewById(R.id.content); final Handler handler=new Handler(Looper.myLooper()); //foundDevice=(ImageView)findViewById(R.id.foundDevice); button=findViewById(R.id.centerImage); rippleBackground.startRippleAnimation(); Intent intent=new Intent(); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { intent.setClass(IndexActivity.this,MainActivity.class); startActivity(intent); } }); } }
RippleBackground.java
package com.example.rubikrobot; import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.RelativeLayout; import java.util.ArrayList; public class RippleBackground extends RelativeLayout{ private static final int DEFAULT_RIPPLE_COUNT=6; private static final int DEFAULT_DURATION_TIME=3000; private static final float DEFAULT_SCALE=6.0f; private static final int DEFAULT_FILL_TYPE=0; private int rippleColor; private float rippleStrokeWidth; private float rippleRadius; private int rippleDurationTime; private int rippleAmount; private int rippleDelay; private float rippleScale; private int rippleType; private Paint paint; private boolean animationRunning=false; private AnimatorSet animatorSet; private ArrayList<Animator> animatorList; private LayoutParams rippleParams; private ArrayList<RippleView> rippleViewList=new ArrayList<RippleView>(); public RippleBackground(Context context) { super(context); } public RippleBackground(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public RippleBackground(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(final Context context, final AttributeSet attrs) { if (isInEditMode()) return; if (null == attrs) { throw new IllegalArgumentException("Attributes should be provided to this view,"); } final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleBackground); rippleColor=typedArray.getColor(R.styleable.RippleBackground_rb_color, getResources().getColor(R.color.rippelColor)); rippleStrokeWidth=typedArray.getDimension(R.styleable.RippleBackground_rb_strokeWidth, getResources().getDimension(R.dimen.rippleStrokeWidth)); rippleRadius=typedArray.getDimension(R.styleable.RippleBackground_rb_radius,getResources().getDimension(R.dimen.rippleRadius)); rippleDurationTime=typedArray.getInt(R.styleable.RippleBackground_rb_duration,DEFAULT_DURATION_TIME); rippleAmount=typedArray.getInt(R.styleable.RippleBackground_rb_rippleAmount,DEFAULT_RIPPLE_COUNT); rippleScale=typedArray.getFloat(R.styleable.RippleBackground_rb_scale,DEFAULT_SCALE); rippleType=typedArray.getInt(R.styleable.RippleBackground_rb_type,DEFAULT_FILL_TYPE); typedArray.recycle(); rippleDelay=rippleDurationTime/rippleAmount; paint = new Paint(); paint.setAntiAlias(true); if(rippleType==DEFAULT_FILL_TYPE){ rippleStrokeWidth=0; paint.setStyle(Paint.Style.FILL); }else paint.setStyle(Paint.Style.STROKE); paint.setColor(rippleColor); rippleParams=new LayoutParams((int)(2*(rippleRadius+rippleStrokeWidth)),(int)(2*(rippleRadius+rippleStrokeWidth))); rippleParams.addRule(CENTER_IN_PARENT, TRUE); animatorSet = new AnimatorSet(); animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); animatorList=new ArrayList<Animator>(); for(int i=0;i<rippleAmount;i++){ RippleView rippleView=new RippleView(getContext()); addView(rippleView,rippleParams); rippleViewList.add(rippleView); final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleX", 1.0f, rippleScale); scaleXAnimator.setRepeatCount(ObjectAnimator.INFINITE); scaleXAnimator.setRepeatMode(ObjectAnimator.RESTART); scaleXAnimator.setStartDelay(i * rippleDelay); scaleXAnimator.setDuration(rippleDurationTime); animatorList.add(scaleXAnimator); final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleY", 1.0f, rippleScale); scaleYAnimator.setRepeatCount(ObjectAnimator.INFINITE); scaleYAnimator.setRepeatMode(ObjectAnimator.RESTART); scaleYAnimator.setStartDelay(i * rippleDelay); scaleYAnimator.setDuration(rippleDurationTime); animatorList.add(scaleYAnimator); final ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rippleView, "Alpha", 1.0f, 0f); alphaAnimator.setRepeatCount(ObjectAnimator.INFINITE); alphaAnimator.setRepeatMode(ObjectAnimator.RESTART); alphaAnimator.setStartDelay(i * rippleDelay); alphaAnimator.setDuration(rippleDurationTime); animatorList.add(alphaAnimator); } animatorSet.playTogether(animatorList); } private class RippleView extends View{ public RippleView(Context context) { super(context); this.setVisibility(View.INVISIBLE); } @Override protected void onDraw(Canvas canvas) { int radius=(Math.min(getWidth(),getHeight()))/2; canvas.drawCircle(radius,radius,radius-rippleStrokeWidth,paint); } } public void startRippleAnimation(){ if(!isRippleAnimationRunning()){ for(RippleView rippleView:rippleViewList){ rippleView.setVisibility(VISIBLE); } animatorSet.start(); animationRunning=true; } } public void stopRippleAnimation(){ if(isRippleAnimationRunning()){ animatorSet.end(); animationRunning=false; } } public boolean isRippleAnimationRunning(){ return animationRunning; } }
layout
<?xml version="1.0" encoding="utf-8"?> <com.example.rubikrobot.RippleBackground xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#A2DAEC" android:id="@+id/content" app:rb_color="#0099CC" app:rb_radius="32dp" app:rb_rippleAmount="6" app:rb_duration="3000" app:rb_scale="6"> <Button android:layout_width="64dp" android:layout_height="64dp" android:layout_centerInParent="true" android:id="@+id/centerImage" android:text="启动" android:textColor="@color/white" android:background="@drawable/ic_blue" /> </com.example.rubikrobot.RippleBackground>
效果图:
这是三个主要文件,剩下的没有展示。
链接:Github
参考文档以及链接均来自于:【Android开发】安卓炫酷效果集合