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

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

先上效果图:



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





项目结构:

主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 816B Karen and Coffee【前缀和/差分】

    To stay woke and attentive during classes, Karen needs some coffee! Karen, a coffee aficionado, want ...

  2. P3197越狱

    花费了好长时间,终于刷掉了这道题. 题目在这里(洛谷)  (信息学奥赛一本通) 嗯,没错,这是一道快速幂的题,不会快速幂点这里 好现在开始分析,这道题用小学奥数的思想就可以想到,直接算有多少种可能比较 ...

  3. CentOS 7.1 中文正式版下载 - 最流行的免费开源企业级 Linux 服务器操作系统

    如果说 Ubuntu 是现今最受桌面用户欢迎的 Linux 操作系统,那么 CentOS 就是最受公司.企业.IDC 喜爱的 Linux 发行版了.得益于极为出色的稳定性,全球范围内无数著名网站均选用 ...

  4. HDOJ 4961 Boring Sum

    Discription Number theory is interesting, while this problem is boring. Here is the problem. Given a ...

  5. HashMap源码分析(Java8)

    1. HashMap public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, ...

  6. 动态NAT地址转换

    1.配置路由器的端口ip地址(注意外网和内网ip地址的设置) Router(config)#inter f0/0 Router(config-if)#ip add 192.168.1.1 255.25 ...

  7. GNS3 思科模块 说明

    GNS3整合了如下的软件:   Dynamips :一款可以让用户直接运行Cisco系统(IOS)的模拟器   Dynagen :是Dynamips的文字显示前端   Pemu : PIX防火墙设备模 ...

  8. Bootstrap标签Tabs

    <!--标签--> <ul class="nav nav-tabs" role="tablist"> <li class=&quo ...

  9. Django入门与实践

    安装: 1.https://www.djangoproject.com/查找最新版本 2.pip install Django==1.10.6安装Django   创建项目: 1.打开命令行,进入想要 ...

  10. JavaScript获取table中某一列的值的方法

    1.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...