支付宝咻一咻怎么用 Android帮你实现咻一咻
作者:Git_Android 发布时间:2023-01-31 03:34:09
对于之前最火的无外乎集五福了,而五福除了加十个好友获得外,最直接的途径就是支付宝的咻一咻了。那么咻一咻具体有哪些实现方式呢?下面我们将一一介绍这几种思路的实现过程。
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">
<ImageButton
android: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">
<objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="1.2"
android:valueType="floatType">
</objectAnimator>
<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:valueFrom="1.0"
android:valueTo="1.2"
android:valueType="floatType">
</objectAnimator>
<objectAnimator
android:startOffset="1000"
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.2"
android:valueTo="1.0"
android:valueType="floatType">
</objectAnimator>
<objectAnimator
android: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">
<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType">
</objectAnimator>
<objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType">
</objectAnimator>
</set>
猜你喜欢
- .sln:解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需的信息。.csproj:项目文件,创建应用程序所需的引用、数据连接
- 网上的文章基本上都是只有多数据源或只有动态数据源,而最近的项目需要同时使用两种方式,记录一下配置方法供大家参考。应用场景项目需要同时连接两个
- 什么是EurekaEureka是Netfilx开源的一个用来实现微服务的注册与发现的组件。它包含Server和Client两部分。为什么要有
- 由于之前一直在使用spring-boot开发,但一直苦恼于不知道如何利用debug调试代码.在网上查找了很多文章之后。学习之余决定把spri
- 一、问题Flutter原有的图片缓存机制,是通过PaintingBinding.instance!.imageCache来管理缓存的,这个缓
- 本文实例讲述了Android手机获取root权限并实现关机重启功能的方法,是Android程序设计中非常常见的重要功能。现分享给大家,供大家
- 前言在我们用户登录的时候,为了安全性考虑,会增加验证码的功能,这里采用的是google的kaptcha;spirngboot是轻便,独立,使
- 今天要介绍一个概念,对象的克隆。本篇有一定难度,请先做好心理准备。看不懂的话可以多看两遍,还是不懂的话,可以在下方留言,我会看情况进行修改和
- 本文实例讲述了Android之复选框对话框用法。分享给大家供大家参考。具体如下:main.xml布局文件<?xml version=&
- 本文实例讲述了Android开发实现webview中img标签加载本地图片的方法。分享给大家供大家参考,具体如下:在网上查了很多教程,感觉很
- .NET将关于多线程的功能定义在System.Threading名字空间中。因此,要使用多线程,必须先声明引用此名字空间(using Sys
- 你要学会:流的概念处理字节流的类处理字符流的类Java标准输入输出文件管理类Java语言的输入输出类库1.流的概念流是指计算机各部件之间的数
- 修改\packages\apps\Camera\res\values\arrays.xml中的以下代码: <string-array
- 前言之前实现过《Android可签到的日历控件》的功能,跟这篇一样都是实现签到打卡功能,这篇实现的是按月进行打卡做标识,本篇内容实现的按周进
- JAVA文件下载时乱码有两种情况:1,下载时中文文件名乱码2,下载时因为路径中包含中文文件名乱码,提示找不到文件解决方法见下面部分代码res
- 本文实例为大家分享了PhotoView实现图片双击放大单击退出的具体代码,供大家参考,具体内容如下实现思路1.复制PhotoView&nbs
- 一、什么是Memcached?Memcached是danga.com开发的分布式内存对象缓存系统,所谓分布式,意味着它不是本地的,而是基于网
- 一个项目可能会有不同的环境,例如dev/stating/prod等,不同的环境的配置文件是不同的,如何根据环境快速的切换到对应的配置文件很重
- 本文总结了我在学习hibernate的过程中,解决hibernate懒加载问题的四种方式。所谓懒加载(lazy)就是延时加载,延迟加载。什么
- LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量