android圆形波纹按钮,android自定义View——圆形波纹扫描效果
蓝牙项目,考虑到后面可能会用到这个扫描的效果,所以参照大神写好的控件,增加了自己需要使用的接口。也顺便巩固一下自定义view中各种零碎的知识点。
需要的效果图
先放一个效果图,点击中心图片开始动画,再次点击结束动画:
先来思路:
可以看到,这个动画是由圆和图片构成,中心图片画出来,然后根据中心图片的大小确定创建波纹时的半径,波纹的最大半径为当前view的宽高较小的。
动画部分,主要使用runable延时 + ValueAnimator 实现波纹效果; 然后整体旋转。
代码来说话。
attrs中定义好需要在xml中设置的变量
部分成员变量注释,方便代码阅读
//波纹生成时的半径
private float mWaveRadiusMin;
//波纹消失前的半径
private float mWaveRadiusMax;
//每条波纹持续时间
private long mWaveDuration;
//波纹生成速度
private long mWaveCreatedSpeed;
private Paint mPaint;
//画笔是否为stroke模式(即线条)
private boolean stroke = false;
//中间图标画笔
private Paint mCenterBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
//中间图标区域
private Rect mCenterBitmapArea = new Rect();
//波纹颜色
private int mWaveColor;
//波纹动画效果
private Interpolator mInterpolator = new AccelerateInterpolator();
//所有的水波纹
private List mAnimatorList = new ArrayList<>();
//是否开启水波纹
private boolean mIsRuning = false;
//是否点击了中间图标
private boolean mIsCenterClick = false;
//中间的图标
private Bitmap mCenterBitmap;
//中间的圆形图标
private Bitmap mCenterCircleBitmap;
//旋转动画
private Animation operatingAnim;
构造方法
public WaveCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.WaveCircleView, 0, defStyleAttr);
for (int i = 0; i < typedArray.length(); i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.WaveCircleView_color:
mWaveColor = typedArray.getColor(attr, Color.BLUE);
break;
case R.styleable.WaveCircleView_image:
mCenterBitmap = BitmapFactory.decodeResource(getResources(),
typedArray.getResourceId(attr, R.mipmap.translate));
break;
case R.styleable.WaveCircleView_duration:
mWaveDuration = typedArray.getInteger(attr, 3000);
break;
case R.styleable.WaveCircleView_waveCreateSpeed:
mWaveCreatedSpeed = typedArray.getInteger(attr, 1000);
break;
case R.styleable.WaveCircleView_stroke:
stroke = typedArray.getBoolean(attr, false);
break;
}
}
typedArray.recycle();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(3);
mPaint.setColor(mWaveColor);
mPaint.setDither(true);
if (stroke)//如果xml中设置为false,就把画笔属性设置为Stroke,最后的效果是线条
mPaint.setStyle(Paint.Style.STROKE);
else//填充效果
mPaint.setStyle(Paint.Style.FILL);
if (mCenterBitmap == null) {
mCenterBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.translate);
mWaveRadiusMin = Math.min(mCenterBitmap.getWidth(), mCenterBitmap.getHeight()) / 2;
}
mWaveRadiusMin = Math.min(mCenterBitmap.getWidth(), mCenterBitmap.getHeight()) / 2;
}
onDraw()中 ,先把中心图片渲染到画布
if (mCenterCircleBitmap == null) {
mCenterCircleBitmap = createCircleImage(mCenterBitmap, mCenterBitmap.getWidth());
}
canvas.drawBitmap(mCenterCircleBitmap, null, mCenterBitmapArea, mCenterBitmapPaint);
private Bitmap createCircleImage(Bitmap source, int min) {
final Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap target = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888);
//产生一个同样大小的画布
Canvas canvas = new Canvas(target);
//首先绘制圆形
canvas.drawCircle(min / 2, min / 2, min / 2, paint);
//使用SRC_IN
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//绘制图片
canvas.drawBitmap(source, 0, 0, paint);
return target;
}
波纹效果
使用runable实现循环更新UI
private Runnable mWaveRunable = new Runnable() {
@Override
public void run() {
if (mIsRuning) {
createWaveAnimator();
invalidate();
//延时循环
postDelayed(mWaveRunable, mWaveCreatedSpeed);
}
}
};
private ValueAnimator createWaveAnimator() {
final ValueAnimator mWaveAnimator = new ValueAnimator();
mWaveAnimator.setFloatValues(mWaveRadiusMin, mWaveRadiusMax);
mWaveAnimator.setDuration(mWaveDuration);
mWaveAnimator.setRepeatCount(0);
mWaveAnimator.setInterpolator(mInterpolator);
mWaveAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
});
//将生成的ValueAnimator存储在list里
mAnimatorList.add(mWaveAnimator);
//开始动画
mWaveAnimator.start();
return mWaveAnimator;
}
onDraw()中绘制波纹,根据动画集合中存储的AnimatedValue 改变画笔透明度 和 canvas 时圆的radius,完成扩散渐隐效果
Iterator iterator = mAnimatorList.iterator();
while (iterator.hasNext()) {
ValueAnimator valueAnimator = iterator.next();
// Log.e("AnimatedValue",(float)valueAnimator.getAnimatedValue() + "mWaveRadiusMax:" + mWaveRadiusMax);
if (!valueAnimator.getAnimatedValue().equals(mWaveRadiusMax)) {
//设置透明度
mPaint.setAlpha(getAlpha((Float) valueAnimator.getAnimatedValue()));
//画水波纹
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, (Float) valueAnimator.getAnimatedValue(), mPaint);
} else {
valueAnimator.cancel();
iterator.remove();
}
}
getAlpha()方法:
private int getAlpha(float mRadius) {
int alpha = 1;
if (mWaveRadiusMax > 0) {
alpha = (int) ((1 - (mRadius - mWaveRadiusMin) / (mWaveRadiusMax - mWaveRadiusMin)) * 255);
}
return alpha;
}
最后,onTouchEvent()实现点击中心控制动画开关
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
//判断是否点击在中心图片范围内
mIsCenterClick = false;
//mCenterBitmapArea 方法在onSizeChanged()中初始化
if (mCenterBitmapArea.contains((int) event.getX(), (int) event.getY())) {
mIsCenterClick = true;
}
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (mIsCenterClick && !mIsRuning) {
//当点击了按钮,启动水波纹
start();
} else {
stop();
}
break;
}
return true;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWaveRadiusMax = Math.min(w, h) / 2;
//计算中间图标区域
mCenterBitmapArea.set((w - mCenterBitmap.getWidth()) / 2, (h - mCenterBitmap.getHeight()) / 2
, (w + mCenterBitmap.getWidth()) / 2, (h + mCenterBitmap.getHeight()) / 2);
}
public void start() {
if (!mIsRuning) {
mIsRuning = true;
mWaveRunable.run();
//旋转效果
operatingAnim = AnimationUtils.loadAnimation(getContext(), R.anim.roa);
LinearInterpolator lin = new LinearInterpolator();
operatingAnim.setInterpolator(lin);
operatingAnim.setDuration(mWaveDuration);
startAnimation(operatingAnim);
}
}
anim中定义的旋转动画以及使用
android:fromDegrees="0"
android:toDegrees="360"
android:repeatCount="-1"
android:pivotX="50%"
android:pivotY="50%" />
最后 , xml中测试
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:color="@color/colorAccent"
app:stroke="true"
app:duration="3000"
app:waveCreateSpeed="500"
app:image="@mipmap/bluetooth"
/>
由于没有写onMeasure(),所以wrap_content占据父控件的全部大小
效果如下:
当然,部分需要用到的属性,也通过getter 和setter暴露出去,方便java代码中灵活控制。
。。。。以后应该能用上
代码中可能还有笔者未发现的bug和暂时不想解决的bug。。。欢迎交流~~~
android圆形波纹按钮,android自定义View——圆形波纹扫描效果相关推荐
- android实现喇叭播放效果图,自定义View 实现音频播放效果
这已经是第二次实现这种效果了.记录下来. 首先看下效果图.这里就不搞gif 了 image.png 1.首先确定需要音频条得数量 2.根据大小计算出 间距和音频条得宽度 3.绘制初始样式 4.利用ha ...
- Android 自定义View 圆形圆角图片
[Android 自定义View 圆形圆角图片] 基于Xfermode 实现 1.概述 在很久以前也写过一个利用Xfermode 实现圆形.圆角图片的(Android 完美实现图片圆角和圆形(对实现进 ...
- android波纹效果弹窗,Android自定义View实现波纹效果
Android自定义View实现波纹效果 时间:2017-05-27 来源:移动互联网学院 1.引言:随着Android智能手机的普及,Android应用得到了大力支持,而Android应用的 ...
- android 高仿ios开关,Android自定义view仿IOS开关效果
本文主要讲解如何在 Android 下实现高仿 iOS 的开关按钮,并非是在 Android 自带的 ToggleButton 上修改,而是使用 API 提供的 onDraw.onMeasure.Ca ...
- Android软件开发之盘点自定义View界面大合集(二)
Android软件开发之盘点自定义View界面大合集(二) - 雨松MOMO的程序世界 - 51CTO技术博客 雨松MOMO带大家盘点Android 中的自定义View界面的绘制 今天我用自己写的一个 ...
- 自定义view圆形头像
自定义view圆形头像 我已经将源码打包成依赖 朋友们可以直接导依赖直接使用 1.正常导入: implementation 'com.github.LiHangKun:wuyuewuone:1' im ...
- android 仿360浮动,Android仿360悬浮小球自定义view实现示例
Android仿360悬浮小球自定义view实现示例 效果图如下: 实现当前这种类似的效果 和360小球 悬浮桌面差不错类似.这种效果是如何实现的呢.废话不多说 ,直接上代码. 1.新建工程,添加悬浮 ...
- Android中实现Bitmap在自定义View中的放大与拖动
一基本实现思路: 基于View类实现自定义View –MyImageView类.在使用View的Activity类中完成OnTouchListener接口,实现对MotionEvent事件的监听与处理 ...
- android 图片圆角 遮罩_Android 自定义View练手Demo(一)实现圆角遮罩效果
Android 自定义View系列文章 Android自定义View实现圆角遮罩效果 一图胜千言,有一个遮罩就会凸显出重点区域 1-1.jpg 本文通过两种方式来实现这种效果,来达到自定义View练手 ...
- Carson带你学Android:源码解析自定义View Draw过程
前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全.思路不清晰.无源码分析.简单问题复杂化 等 今天,我将全面总结自定义View ...
最新文章
- 隐藏滚动条,保留鼠标滚动效果
- 如何在eclipse中自定义一个jar包名称
- BFS简单搜索--POJ 2243
- 系列TCP/IP协议-动态IP选路协议(008)
- 炼数成金数据分析课程---16、机器学习中的分类算法(交叉内容,后面要重点看)...
- 实验6 实践课程中的程序
- QObject::startTimer: Timers cannot be started from another thread
- 复合选择器-子选择器(HTML、CSS)
- C语言的标准内存分配函数
- think php5关联模型,thinkphp5 关联模型
- 室外定位篇:一文解读高精度RTK定位
- PostScript语言里的珠玑
- linux运行崩溃怎么定位,Linux 程序崩溃定位
- 摩斯代码在线html,HTML5 摩斯(Morse)电码生成器
- peoplesoft 日志
- 【机器人基础】阻抗/导纳控制深度解析
- mysql 代码书写,【单选题】mysql 的代码书写规则是()
A. 不区分大小写 B. 必须全部大写 C. 必须全部小写 D. 以上答案都不对...
- Teamcenter8 更改料号所有者操作
- 工业控制系统安全评估流程威胁事件构建
- 第五章 面向对象(上)