转载请注明出处:王亟亟的大牛之路

如今各种各样的进度条的呈现方式各种各样,我们老旧的条状条子和转圈圈的方式已经无法满足我们的业务需求,今天亟亟上的是一个水滴状循环滚动的一个自己定义视图。你能够把他用在各种不同的场景下。

先上效果图:



然后又加入了真空,隐藏和显示的效果,如图。





项目结构:

主Activity

public class MainActivity extends AppCompatActivity {

    private MetaballView metaballView;

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
metaballView = (MetaballView) this.findViewById(R.id.metaball);
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_fill) {
metaballView.setPaintMode(1);
return true;
} else if (id == R.id.action_strock) {
metaballView.setPaintMode(0);
return true;
}else if(id==R.id.action_disappear){
metaballView.setVisibility(View.GONE);
return true;
}else if(id==R.id.action_appear){
metaballView.setVisibility(View.VISIBLE);
return true;
} return super.onOptionsItemSelected(item);
}
}

CustomView

public class MetaballView extends View {

    private Paint paint = new Paint();
private float handle_len_rate = 2f;
private float radius = 30;
private final int ITEM_COUNT = 6;
private final int ITEM_DIVIDER = 60;
private final float SCALE_RATE = 0.3f;
private float maxLength;
private ArrayList<Circle> circlePaths = new ArrayList<>();
private float mInterpolatedTime;
private MoveAnimation wa;
private Circle circle; public MetaballView(Context context) {
super(context);
init();
} public MetaballView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} public MetaballView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(); } private class Circle {
float[] center;
float radius;
} public void setPaintMode(int mode) {
paint.setStyle(mode == 0 ? Paint.Style.STROKE : Paint.Style.FILL);
} private void init() {
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
Circle circlePath = new Circle();
circlePath.center = new float[]{(radius + ITEM_DIVIDER), radius * 1.4f};
circlePath.radius = radius / 4 * 3;
circlePaths.add(circlePath); for (int i = 1; i < ITEM_COUNT; i++) {
circlePath = new Circle();
circlePath.center = new float[]{(radius * 2 + ITEM_DIVIDER) * i, radius * 1.4f};
circlePath.radius = radius;
circlePaths.add(circlePath);
}
maxLength = (radius * 2 + ITEM_DIVIDER) * ITEM_COUNT;
} private float[] getVector(float radians, float length) {
float x = (float) (Math.cos(radians) * length);
float y = (float) (Math.sin(radians) * length);
return new float[]{
x, y
};
} private class MoveAnimation extends Animation { @Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
mInterpolatedTime = interpolatedTime;
invalidate();
}
} /**
* @param canvas 画布
* @param j
* @param i
* @param v 控制两个圆连接时候长度,间接控制连接线的粗细。该值为1的时候连接线为直线
* @param handle_len_rate
* @param maxDistance
*/
private void metaball(Canvas canvas, int j, int i, float v, float handle_len_rate, float maxDistance) {
final Circle circle1 = circlePaths.get(i);
final Circle circle2 = circlePaths.get(j); RectF ball1 = new RectF();
ball1.left = circle1.center[0] - circle1.radius;
ball1.top = circle1.center[1] - circle1.radius;
ball1.right = ball1.left + circle1.radius * 2;
ball1.bottom = ball1.top + circle1.radius * 2; RectF ball2 = new RectF();
ball2.left = circle2.center[0] - circle2.radius;
ball2.top = circle2.center[1] - circle2.radius;
ball2.right = ball2.left + circle2.radius * 2;
ball2.bottom = ball2.top + circle2.radius * 2; float[] center1 = new float[]{
ball1.centerX(),
ball1.centerY()
};
float[] center2 = new float[]{
ball2.centerX(),
ball2.centerY()
};
float d = getDistance(center1, center2); float radius1 = ball1.width() / 2;
float radius2 = ball2.width() / 2;
float pi2 = (float) (Math.PI / 2);
float u1, u2; if (d > maxDistance) {
canvas.drawCircle(ball1.centerX(), ball1.centerY(), circle1.radius, paint);
canvas.drawCircle(ball2.centerX(), ball2.centerY(), circle2.radius, paint);
} else {
float scale2 = 1 + SCALE_RATE * (1 - d / maxDistance);
float scale1 = 1 - SCALE_RATE * (1 - d / maxDistance);
radius2 *= scale2;
// radius1 *= scale1;
canvas.drawCircle(ball1.centerX(), ball1.centerY(), radius1, paint);
canvas.drawCircle(ball2.centerX(), ball2.centerY(), radius2, paint); } Log.d("Metaball_radius", "radius1:" + radius1 + ",radius2:" + radius2);
if (radius1 == 0 || radius2 == 0) {
return;
} if (d > maxDistance || d <= Math.abs(radius1 - radius2)) {
return;
} else if (d < radius1 + radius2) {
u1 = (float) Math.acos((radius1 * radius1 + d * d - radius2 * radius2) /
(2 * radius1 * d));
u2 = (float) Math.acos((radius2 * radius2 + d * d - radius1 * radius1) /
(2 * radius2 * d));
} else {
u1 = 0;
u2 = 0;
}
Log.d("Metaball", "center2:" + Arrays.toString(center2) + ",center1:" + Arrays.toString(center1));
float[] centermin = new float[]{center2[0] - center1[0], center2[1] - center1[1]}; float angle1 = (float) Math.atan2(centermin[1], centermin[0]);
float angle2 = (float) Math.acos((radius1 - radius2) / d);
float angle1a = angle1 + u1 + (angle2 - u1) * v;
float angle1b = angle1 - u1 - (angle2 - u1) * v;
float angle2a = (float) (angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v);
float angle2b = (float) (angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v); Log.d("Metaball", "angle1:" + angle1 + ",angle2:" + angle2 + ",angle1a:" + angle1a + ",angle1b:" + angle1b + ",angle2a:" + angle2a + ",angle2b:" + angle2b); float[] p1a1 = getVector(angle1a, radius1);
float[] p1b1 = getVector(angle1b, radius1);
float[] p2a1 = getVector(angle2a, radius2);
float[] p2b1 = getVector(angle2b, radius2); float[] p1a = new float[]{p1a1[0] + center1[0], p1a1[1] + center1[1]};
float[] p1b = new float[]{p1b1[0] + center1[0], p1b1[1] + center1[1]};
float[] p2a = new float[]{p2a1[0] + center2[0], p2a1[1] + center2[1]};
float[] p2b = new float[]{p2b1[0] + center2[0], p2b1[1] + center2[1]}; Log.d("Metaball", "p1a:" + Arrays.toString(p1a) + ",p1b:" + Arrays.toString(p1b) + ",p2a:" + Arrays.toString(p2a) + ",p2b:" + Arrays.toString(p2b)); float[] p1_p2 = new float[]{p1a[0] - p2a[0], p1a[1] - p2a[1]}; float totalRadius = (radius1 + radius2);
float d2 = Math.min(v * handle_len_rate, getLength(p1_p2) / totalRadius);
d2 *= Math.min(1, d * 2 / (radius1 + radius2));
Log.d("Metaball", "d2:" + d2);
radius1 *= d2;
radius2 *= d2; float[] sp1 = getVector(angle1a - pi2, radius1);
float[] sp2 = getVector(angle2a + pi2, radius2);
float[] sp3 = getVector(angle2b - pi2, radius2);
float[] sp4 = getVector(angle1b + pi2, radius1);
Log.d("Metaball", "sp1:" + Arrays.toString(sp1) + ",sp2:" + Arrays.toString(sp2) + ",sp3:" + Arrays.toString(sp3) + ",sp4:" + Arrays.toString(sp4)); Path path1 = new Path();
path1.moveTo(p1a[0], p1a[1]);
path1.cubicTo(p1a[0] + sp1[0], p1a[1] + sp1[1], p2a[0] + sp2[0], p2a[1] + sp2[1], p2a[0], p2a[1]);
path1.lineTo(p2b[0], p2b[1]);
path1.cubicTo(p2b[0] + sp3[0], p2b[1] + sp3[1], p1b[0] + sp4[0], p1b[1] + sp4[1], p1b[0], p1b[1]);
path1.lineTo(p1a[0], p1a[1]);
path1.close();
canvas.drawPath(path1, paint); } private float getLength(float[] b) {
return (float) Math.sqrt(b[0] * b[0] + b[1] * b[1]);
} private float getDistance(float[] b1, float[] b2) {
float x = b1[0] - b2[0];
float y = b1[1] - b2[1];
float d = x * x + y * y;
return (float) Math.sqrt(d);
} //測试用
// @Override
// public boolean onTouchEvent(MotionEvent event) {
// switch (event.getAction()) {
// case MotionEvent.ACTION_DOWN:
// break;
// case MotionEvent.ACTION_MOVE:
// Circle circle = circlePaths.get(0);
// circle.center[0] = event.getX();
// circle.center[1] = event.getY();
// invalidate();
// break;
// case MotionEvent.ACTION_UP:
// break;
// }
//
// return true;
// } @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
circle = circlePaths.get(0);
circle.center[0] = maxLength * mInterpolatedTime;
for (int i = 1, l = circlePaths.size(); i < l; i++) {
metaball(canvas, i, 0, 0.6f, handle_len_rate, radius * 4f);
}
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (ITEM_COUNT * (radius * 2 + ITEM_DIVIDER)), MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (2 * radius * 1.4f), MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} private void stopAnimation() {
this.clearAnimation();
postInvalidate();
} private void startAnimation() {
wa = new MoveAnimation();
wa.setDuration(2500);
wa.setInterpolator(new AccelerateDecelerateInterpolator());
wa.setRepeatCount(Animation.INFINITE);
wa.setRepeatMode(Animation.REVERSE);
startAnimation(wa);
} @Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility); if (visibility == GONE || visibility == INVISIBLE) {
stopAnimation();
} else {
startAnimation();
}
} @Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
startAnimation();
} @Override
protected void onDetachedFromWindow() {
stopAnimation();
super.onDetachedFromWindow();
} }

想改变呈现的方式能够改动Style文件以及setColor这里更改自己想要的颜色。也能够改构造函数用外部传入的方式来活用该类

布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#001d30"
android:clipChildren="false"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"> <com.dodola.animview.MetaballView
android:id="@+id/metaball"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>

源代码已上传,地址:http://yunpan.cn/cddIXXQbqTf2m 訪问password 681c

有问题或者有业务QQ452270579交流,谢谢

水滴状的自己定义视图,让您摆脱单调的Dialog的更多相关文章

  1. ANDROID自己定义视图——onLayout源代码 流程 思路具体解释

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 简单介绍: 在自己定义view的时候.事实上非常easy.仅仅须要知道3步骤: 1.測量- ...

  2. django基础知识之定义视图:

    定义视图 本质就是一个函数 视图的参数 一个HttpRequest实例 通过正则表达式组获取的位置参数 通过正则表达式组获得的关键字参数 在应用目录下默认有views.py文件,一般视图都定义在这个文 ...

  3. Django 定义视图函数

    Django 定义视图函数 一.接收内容及文件处理 1.接收分类 # 获取数据 request.GET # 提交数据 request.POST # 获取文件 request.FILES 2.check ...

  4. 【读书笔记】iOS-自定义视图的创建

    静态创建自定义视图就是以拖动的方法来创建. 动态创建自定义视图可以理解为使用代码来创建自定义视图. 参考资料:<iOS7开发快速入门>

  5. SpringMvc-自定义视图

    1.创建视图: 注意:创建视图的时候需要实现View接口的俩个方法 package com.atguigu.springmvc.views; import java.util.Date; import ...

  6. mvc-自定义视图引擎

    //自定义视图引擎的实质是把数据模型(moudle)和模板(View)转换成html页面,输出到客户端public class MyView:IView { string _viewPath; pub ...

  7. Andriod三步学会安卓自己定义视图及其属性

    第一步:自己定义属性 第二步:自己定义控件解析属性 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcm5adW9adW8=/font/5a6L5L2T/fo ...

  8. Django学习(五) 定义视图以及页面模板

    请求解析一般都是通过请求的request获取一定参数,然后根据参数做一定业务逻辑判断,这其中可能包括查询数据库,然后将需要返回的数据封装成一个HttpResponse返回. 代码如下: 这是一个简单的 ...

  9. Android自己定义视图(一):带下划线的TextView

    package com.francis.underlinetextviewtest; import android.content.Context; import android.content.re ...

随机推荐

  1. CF 990C. Bracket Sequences Concatenation Problem【栈/括号匹配】

    [链接]:CF [题意]: 给出n个字符串,保证只包含'('和')',求从中取2个字符串链接后形成正确的括号序列的方案数(每个串都可以重复使用)(像'()()'和'(())'这样的都是合法的,像')( ...

  2. 哦这。。!C语言scanf输入的坑爹之处

    一. 今天闲来无事,跑去A题,本想3sA了poj1004,结果搞了10分钟,最令人困惑的问题就是为什么定义了double类型的变量,但是用scanf输入的时候标识符用%f的话,输入并不能完成,也就是说 ...

  3. ( 转 ) mysql 实战 or、in与union all 的查询效率

    OR.in和union all 查询效率到底哪个快. 网上很多的声音都是说union all 快于 or.in,因为or.in会导致全表扫描,他们给出了很多的实例. 但真的union all真的快于o ...

  4. JVM内存溢出及配置

    一.Java JVM内存介绍 JVM管理两种类型的内存,堆和非堆.按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚拟机启动时创 ...

  5. String和StringBuffer的机制差别

    String是不可变的,StringBuffer是可变的:StringBuffer是线程安全的,StringBuilder是非线程安全的. 因而在大部分情况下字符串的拼接速度为:StringBuild ...

  6. POJ 3246 Game(凸包)

    [题目链接] http://poj.org/problem?id=3246 [题目大意] 给出一些点,请删去一个点,使得包围这些点用的线长最短 [题解] 去掉的点肯定是凸包上的点,所以枚举凸包上的点去 ...

  7. 【二维莫队】【二维分块】bzoj2639 矩形计算

    <法一>二维莫队,对n和m分别分块后,对块从上到下从左到右依次编号,询问以左上角所在块编号为第一关键字,以右下角标号为第二关键字排序,转移时非常厉害. O(q*n*sqrt(n)). #i ...

  8. 【二分答案】【最大流】bzoj1305 [CQOI2009]dance跳舞

    http://hzwer.com/1986.html #include<cstdio> #include<algorithm> #include<queue> #i ...

  9. SpringMVC(流程+第一个Demo)

    一.流程图 用户发送请求至前端控制器DispatcherServlet DispatcherServlet收到请求调用HandlerMapping处理器映射器. 处理器映射器根据请求url找到具体的处 ...

  10. python 使用mysql示例

    安装MySQL驱动 由于MySQL服务器以独立的进程运行,并通过网络对外服务,所以,需要支持Python的MySQL驱动来连接到MySQL服务器.MySQL官方提供了mysql-connector-p ...