对于之前最火的无外乎集五福了,而五福除了加十个好友获得外,最直接的途径就是支付宝的咻一咻了。那么咻一咻具体有哪些实现方式呢?下面我们将一一介绍这几种思路的实现过程。
1.自定义View实现咻一咻那么这种实现方法需要掌握Canvas以及Paint几乎所有的方法。其对程序员的专业知识要求极高。
用该种方式实现的优点有:
- ㈠这种是最复杂的实现方法,但其兼容性最高,其支持android的所有设备。
- ㈡其对内存要求不大,几乎不占用任何内存。
下面我们来看看是怎样实现其效果的:
public class XiuYiXiuView extends View { /**** 中心图片画笔*/ private Paint paint; /**** 水波圆圈画笔*/ private Paint circlePaint; /**** 用bitmap创建画布*/ private Bitmap bitmap; /**** 中心图片*/ private Bitmap imageBit; /**** 画布*/ private Canvas canvas; /**** 屏幕的宽*/ private int screenWidth; /**** 屏幕的高*/ private int screenHeight; /**** 图片右上角坐标*/ private Point pointLeftTop; /**** 图片右下角坐标*/ private Point pointRightBottom; /**** 记录圆圈*/ private List<LYJCircle> lyjCircleList; /**** 标记是否按下按钮,并且源泉是否扩散消失*/ private boolean isSpread=false; /**** 默认没有按动时候的圆圈*/ private LYJCircle defaultCircle; public XiuYiXiuView(Context context, AttributeSet attrs) {super(context, attrs);this.lyjCircleList=new ArrayList<>();screenWidth=LYJUtils.getScreenWidth((Activity) context);screenHeight=LYJUtils.getScreenHeight((Activity) context);bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); // 设置位图的宽高canvas = new Canvas();canvas.setBitmap(bitmap);paint=new Paint(Paint.DITHER_FLAG);paint.setAntiAlias(true);circlePaint=new Paint(Paint.DITHER_FLAG);circlePaint.setAntiAlias(true);imageBit= BitmapFactory.decodeResource(getResources(), R.drawable.bwa_homepage_yuyin);pointLeftTop=new Point((screenWidth/2)-(imageBit.getWidth()/2),(screenHeight/2)-(imageBit.getHeight()/2));pointRightBottom=new Point(pointLeftTop.x+imageBit.getWidth(),pointLeftTop.y+imageBit.getHeight());canvas.drawBitmap(imageBit,pointLeftTop.x,pointLeftTop.y,paint);//取图片上的颜色Palette.generateAsync(imageBit, new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) {Palette.Swatch swatch1 = palette.getVibrantSwatch(); //充满活力的色板circlePaint.setColor(swatch1.getRgb());circlePaint.setStyle(Paint.Style.STROKE);circlePaint.setStrokeWidth(10);circlePaint.setAlpha(100);paint.setShadowLayer(15, 0, 0, swatch1.getRgb());//设置阴影效果int[] mColors = new int[] {//渲染颜色Color.TRANSPARENT,swatch1.getRgb()};//范围,这里可以微调,实现你想要的渐变float[] mPositions = new float[] {0f, 0.1f};Shader shader=new RadialGradient(screenWidth / 2,screenHeight / 2,imageBit.getWidth() / 2 + 10,mColors, mPositions,Shader.TileMode.MIRROR);circlePaint.setShader(shader);defaultCircle=new LYJCircle(screenWidth / 2, screenHeight / 2, imageBit.getWidth() / 2 + 10);clearScreenAndDrawList();Message message = handler.obtainMessage(1);handler.sendMessageDelayed(message, 1000); //发送message }}); } @Override public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()){ case MotionEvent.ACTION_DOWN:break; case MotionEvent.ACTION_MOVE:break; case MotionEvent.ACTION_UP:isSpread=true;//是否按下图片lyjCircleList.add(new LYJCircle(screenWidth / 2, screenHeight / 2, imageBit.getWidth() / 2 + 10));clearScreenAndDrawList();invalidate();break; default:break;}return true; } private Handler handler = new Handler(){public void handleMessage(Message msg){ switch (msg.what) {case 1: //定时更新界面 clearScreenAndDrawList(); invalidate(); Message message = handler.obtainMessage(1); handler.sendMessageDelayed(message, 200); } super.handleMessage(msg);} }; /*** 清掉屏幕上所有的圆圈,然后画出集合里面的圆圈*/ private void clearScreenAndDrawList() {canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);//判断是否按下图片,并且外圈执行完成没有。if(!isSpread){circlePaint.setMaskFilter(null);canvas.drawCircle(defaultCircle.getRoundX(), defaultCircle.getRoundY(),defaultCircle.getRadiuLoop(), circlePaint);// 画线}else{ for (LYJCircle lyjCircle : lyjCircleList) {if(lyjCircle.getSpreadRadiu()==0){}else if(lyjCircle.getSpreadRadiu()>(lyjCircle.getRadiu()+99)){ //如果圆圈扩散半径大于图片半径+99,那么设置边缘模糊,也就是淡出的效果 circlePaint.setMaskFilter(new BlurMaskFilter(5, BlurMaskFilter.Blur.OUTER)); canvas.drawCircle(lyjCircle.getRoundX(), lyjCircle.getRoundY(),lyjCircle.getSpreadRadiu(), circlePaint);// 画线}else{ //不是则按正常的环形渲染来 circlePaint.setMaskFilter(null); canvas.drawCircle(lyjCircle.getRoundX(), lyjCircle.getRoundY(),lyjCircle.getSpreadRadiu(), circlePaint);// 画线} }}canvas.drawBitmap(imageBit,pointLeftTop.x,pointLeftTop.y,paint);//释放小时了的圆圈for(int i=0;i<lyjCircleList.size();i++){ if(lyjCircleList.get(i).getSpreadRadiu()==0){lyjCircleList.remove(i); }}//如果没有点击图片发射出去的圆圈,那么就恢复默认缩放。if(lyjCircleList.size()<=0){ isSpread=false;} } @Override protected void onDraw(Canvas canvas) {canvas.drawBitmap(bitmap, 0, 0, null); }}圆类:
package com.example.liyuanjing.model;/** * Created by liyuanjing on 2016/2/3. */public class LYJCircle { private int roundX;//圆中心点X坐标 private int roundY;//圆中心点Y坐标 private int radiu;//圆半径 private int currentRadiu;//当前radiu private int lastRadiu;//历史radiu private int spreadRadiu;//加速半径 private int[] speed=new int[]{6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6};//半径扩大速度。这里为匀速 private int speedLast=0;//记录历史值 public LYJCircle(int roundX,int roundY,int radiu){this.roundX=roundX;this.roundY=roundY;this.radiu=radiu;this.spreadRadiu=radiu;this.currentRadiu=this.radiu;this.lastRadiu=this.currentRadiu; } //获取半径 public int getRadiu() {return radiu; } public void setRadiu(int radiu) {this.radiu = radiu; } //获取加速半径 public int getSpreadRadiu(){if(speedLast>=speed.length){ return 0;}spreadRadiu+=speed[speedLast];++speedLast;return spreadRadiu; } //获取循环缩放半径 public int getRadiuLoop() {if(currentRadiu==lastRadiu){ ++currentRadiu;}else if(currentRadiu>lastRadiu){ if(currentRadiu>(radiu+20)){currentRadiu=19+radiu;lastRadiu=20+radiu; }else{lastRadiu=currentRadiu;currentRadiu+=5; }}else{ if(currentRadiu<(radiu+9)){currentRadiu=10+radiu;lastRadiu=9+radiu; }else{lastRadiu=currentRadiu;currentRadiu-=5; }}return currentRadiu; } public int getRoundX() {return roundX; } public int getRoundY() {return roundY; }}你可以修改如下两个地方,会产生视觉上真真的波纹效果:
①支付宝的背景图片是淡红色,衬托了红色的波纹。当然了你也可以将画布设置为透明淡红色。
②其为填充圆圈渲染,不是我的边框渲染效果,你可以将circlePaint.setStyle(Paint.Style.STROKE);换成Paint.Style.FILL.然后,微调shader的mPositions实现环形填充渐变。你也许会觉得,你看支付宝咻一咻圆圈弹开的时候内圈有波纹也像外弹开,其实那就是环形渐变,当你圆圈变大后,其渐变的范围也就变大了,自然你看到有颜色周围扩散的迹象。
2.属性动画实现咻一咻其要掌握的只是基本只需要属性动画,在加一点线程方面有关的知识而已。
下面我们看看其实现步骤:
㈠自定义View实现一个圆即可,代码如下:
public class LYJCircleView extends View { private Bitmap bitmap; private Paint paint; private Canvas canvas; private int screenWidth; private int screenHeight; private boolean isSpreadFlag=false;//标记是否发射完成 public boolean isSpreadFlag() {return isSpreadFlag; } public void setIsSpreadFlag(boolean isSpreadFlag) {this.isSpreadFlag = isSpreadFlag; } public LYJCircleView(Context context,int width,int height,int statusHeight) {super(context);screenWidth= LYJUtils.getScreenWidth((Activity) context);screenHeight=LYJUtils.getScreenHeight((Activity) context);bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); // 设置位图的宽高canvas = new Canvas();canvas.setBitmap(bitmap);paint=new Paint(Paint.DITHER_FLAG);paint.setAntiAlias(true);paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5);paint.setAlpha(100);paint.setShadowLayer(10, 0, 0, Color.RED);int[] mColors = new int[] {Color.TRANSPARENT,Color.RED};float[] mPositions = new float[] {0f, 0.1f};Shader shader=new RadialGradient(screenWidth / 2,screenHeight / 2,width / 2 + 10,mColors, mPositions,Shader.TileMode.MIRROR);paint.setShader(shader);canvas.drawCircle(screenWidth / 2, (screenHeight - statusHeight) / 2, width / 2 + 10, paint);invalidate(); } @Override protected void onDraw(Canvas canvas) {canvas.drawBitmap(bitmap,0,0,null); }}代码与上面差不多,就不注释了。
㈡实现Activity即可
public class XiuYiXiuActivity extends AppCompatActivity { private ImageButton mImageButton; private LYJCircleView lyjCircleView; private RelativeLayout relativeLayout; private List<LYJCircleView> lyjCircleViewList; private int statusBarHeight; private Animator anim; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.xiuyixiu_activity_main);this.mImageButton=(ImageButton)findViewById(R.id.xiuyixiu_imagebutton);this.relativeLayout=(RelativeLayout)findViewById(R.id.xiuyixiu_relativelayout);this.lyjCircleViewList=new ArrayList<>();this.mImageButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {lyjCircleView.setVisibility(View.GONE);//发射圆圈,即将循环动画View隐藏final LYJCircleView item=new LYJCircleView(XiuYiXiuActivity.this, mImageButton.getWidth(), mImageButton.getHeight(), statusBarHeight);Animator spreadAnim = AnimatorInflater.loadAnimator(XiuYiXiuActivity.this, R.animator.circle_spread_animator);spreadAnim.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) {item.setIsSpreadFlag(true);//动画执行完成,标记一下 } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { }});spreadAnim.setTarget(item);spreadAnim.start();lyjCircleViewList.add(item);relativeLayout.addView(item);relativeLayout.invalidate();Message message = handler.obtainMessage(1);handler.sendMessageDelayed(message, 10); //发送message,定时释放LYJCircleView }}); } private Handler handler = new Handler(){public void handleMessage(Message msg){ switch (msg.what) {case 1: for(int i=0;i<lyjCircleViewList.size();i++){if(lyjCircleViewList.get(i).isSpreadFlag()){ relativeLayout.removeView(lyjCircleViewList.get(i)); lyjCircleViewList.remove(i); relativeLayout.invalidate();} } if(lyjCircleViewList.size()<=0){lyjCircleView.setVisibility(View.VISIBLE); } Message message = handler.obtainMessage(1); handler.sendMessageDelayed(message, 10); } super.handleMessage(msg);} }; @Override public void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);//获取状态栏高度Rect frame = new Rect();getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);statusBarHeight = frame.top;this.mImageButton.post(new Runnable() { @Override public void run() {lyjCircleView = new LYJCircleView(XiuYiXiuActivity.this, mImageButton.getWidth(), mImageButton.getHeight(), statusBarHeight);relativeLayout.addView(lyjCircleView);relativeLayout.postInvalidate();// 加载动画anim = AnimatorInflater.loadAnimator(XiuYiXiuActivity.this, R.animator.circle_scale_animator);anim.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) {anim.start();//循环执行动画 } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { }});anim.setTarget(lyjCircleView);anim.start(); }}); }}㈢布局文件代码如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/xiuyixiu_relativelayout" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageButtonandroid:id="@+id/xiuyixiu_imagebutton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="@drawable/bwa_homepage_yuyin"/></RelativeLayout>
当然上面两个实现方法,我都只设置圆边框,没有填充,你可以设置为填充后,在微调渐变值。
其属性动画文件circle_scale_animator.xml:
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together"> <objectAnimatorandroid:duration="1000"android:propertyName="scaleX"android:valueFrom="1.0"android:valueTo="1.2"android:valueType="floatType"> </objectAnimator> <objectAnimatorandroid:duration="1000"android:propertyName="scaleY"android:valueFrom="1.0"android:valueTo="1.2"android:valueType="floatType"> </objectAnimator> <objectAnimatorandroid:startOffset="1000"android:duration="1000"android:propertyName="scaleX"android:valueFrom="1.2"android:valueTo="1.0"android:valueType="floatType"> </objectAnimator> <objectAnimatorandroid:startOffset="1000"android:duration="1000"android:propertyName="scaleY"android:valueFrom="1.2"android:valueTo="1.0"android:valueType="floatType"> </objectAnimator></set>
另一个circle_spread_animator.xml为:
<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimatorandroid:duration="1000"android:propertyName="scaleY"android:valueFrom="1.0"android:valueTo="2.0"android:valueType="floatType"> </objectAnimator> <objectAnimatorandroid:duration="1000"android:propertyName="scaleX"android:valueFrom="1.0"android:valueTo="2.0"android:valueType="floatType"> </objectAnimator></set>
以上就是本文的详细内容,希望对大家的学习有所帮助。