Android自定义View基础篇(二)
来源:互联网 发布:诊所管理系统源码 编辑:程序博客网 时间:2024/05/18 02:20
近来在win10上面看到了加载做得很酷炫,自己也想在Android上实现类似的效果,来看下效果图:
是不是有点类似,首先先讲两种使用方法
使用方法一
和基础控件一样:
<com.github.ws.loadingview.app.LoadingView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="visible" app:ballColor="#00ff00" app:ballNumber="6" />
app:ballColor表示小球的颜色,app:ballNumber表示小球的个数。
使用方法二
LoadingDialog dialog=new LoadingDialog(this); dialog.show();
实现过程
我们看完了使用方法,接下来我们深入到代码中去了解如何实现的。后面我会附上源码及下载地址。
values文件夹新建attrs:
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="LoadingView"> <attr name="ballColor" format="color"></attr> <attr name="ballNumber" format="integer" /> </declare-styleable></resources>
自定义属性:
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LoadingView, defStyleAttr, 0); ballColor = ta.getColor(R.styleable.LoadingView_ballColor, Color.parseColor("#ff0000")); ballNumber = ta.getInteger(R.styleable.LoadingView_ballNumber, 6); ta.recycle();
onMeasure方法:
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(getDefaultMeasureSpec()[0], getDefaultMeasureSpec()[1]); } else if (widthSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(getDefaultMeasureSpec()[0], heightSpecSize); } else if (heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSpecSize, getDefaultMeasureSpec()[1]); }else { setMeasuredDimension(widthSpecSize, heightSpecSize); }
我们需要需要绘制,重写onDraw()方法,我们先来看一张草图,自己画的,不是很清晰凑合着看:
小圆的坐标:
float x = (float) (centerPointX + loadRadius * Math.cos(Math.toRadians(a)));float y = (float) (centerPointY + loadRadius * Math.sin(Math.toRadians(a)));
开始a的角度是-90度,可以从效果图中看到小球运动一圈后会隐藏0.5秒,一圈的角度刚好是360度,当然这是一个小球的角度,当我们有6个小球的情况呢?
if ((angle + BALLS_DISTANCE * (i - (ballNumber - 1))) > CIRCLE_ANGLE) { //第一个小球运动了360度隐藏,最后一个小球运动了360度 ,第一个小球又显示出来。 mPaint.setAlpha(0); if (angle > CIRCLE_ANGLE + BALLS_DISTANCE * (ballNumber - 1)) { handler.sendEmptyMessageDelayed(MSG_BALL_GONE, 500); } } else { mPaint.setAlpha(255); }
sendEmptyMessageDelayed发送了消息,0.5秒后重置小球的位置状态:
if (msg.what == MSG_BALL_GONE) { isShow = true; angle = 0; handler.removeMessages(MSG_BALL_GONE); invalidate(); }
然后就是对isShow的一个状态处理:
if (isShow) { if (angle + BALLS_DISTANCE * i < BALLS_DISTANCE * (ballNumber - 1)) { mPaint.setAlpha(0); } if (angle > BALLS_DISTANCE * (ballNumber - 1)) { isShow = false; } }
源码到这里就解析的差不多了,可能你有更好的办法来实现,我只是通过LoadingView来讲解自定义View的基础过程。如果你有更好的建议可以给我留言。下面是源码:
package com.github.ws.loadingview.app;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.View;import android.view.WindowManager;import com.github.ws.loadingview.R;/** * Created by Administrator on 3/18 0018. */public class LoadingView extends View { private Paint mPaint; private int ballColor; private int angle = 0;//旋转角度 0~360 private int centerPointX; private int centerPointY; private int ballNumber; //默认小球数量为6 private int loadRadius; private int ballRadius; private boolean isShow = false; private static final float LOADING_RADIUS = 1 / 16F; private static final float POINT_RADIUS = 1 / 8F; private static final int MOVE_ANGLE = 8; private static final int MSG_BALL_GONE = 2; private static final int MSG_BALL_VISIBLE = 1; private static final int BALLS_DISTANCE = 32; private static final int CIRCLE_ANGLE = 360; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == MSG_BALL_VISIBLE) { angle += MOVE_ANGLE; handler.removeMessages(MSG_BALL_VISIBLE); invalidate(); } else if (msg.what == MSG_BALL_GONE) { isShow = true; angle = 0; handler.removeMessages(MSG_BALL_GONE); invalidate(); } } }; public LoadingView(Context context) { super(context); init(context); } public LoadingView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LoadingView, defStyleAttr, 0); ballColor = ta.getColor(R.styleable.LoadingView_ballColor, Color.parseColor("#ff0000")); ballNumber = ta.getInteger(R.styleable.LoadingView_ballNumber, 6); ta.recycle(); init(context); } private void init(Context context) { this.setBackgroundColor(Color.parseColor("#6f000000")); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(ballColor); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(getDefaultMeasureSpec()[0], getDefaultMeasureSpec()[1]); } else if (widthSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(getDefaultMeasureSpec()[0], heightSpecSize); } else if (heightSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSpecSize, getDefaultMeasureSpec()[1]); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { loadRadius = (int) (Math.min(w, h) * LOADING_RADIUS); ballRadius = (int) (loadRadius * POINT_RADIUS); centerPointX = w / 2; centerPointY = h / 2; super.onSizeChanged(w, h, oldw, oldh); } private int[] getDefaultMeasureSpec() { WindowManager wm = (WindowManager) getContext().getSystemService( Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); return new int[]{outMetrics.widthPixels, outMetrics.heightPixels}; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < ballNumber; i++) { //90度 开始转动 float x = (float) (centerPointX + loadRadius * Math.cos(Math.toRadians(90 + angle + BALLS_DISTANCE * (i - (ballNumber - 1))))); float y = (float) (centerPointY + loadRadius * Math.sin(Math.toRadians(90 + angle + BALLS_DISTANCE * (i - (ballNumber - 1))))); if ((angle + BALLS_DISTANCE * (i - (ballNumber - 1))) > CIRCLE_ANGLE) { mPaint.setAlpha(0); if (angle > CIRCLE_ANGLE + BALLS_DISTANCE * (ballNumber - 1)) { handler.sendEmptyMessageDelayed(MSG_BALL_GONE, 500); } } else { mPaint.setAlpha(255); } if (isShow) { if (angle + BALLS_DISTANCE * i < BALLS_DISTANCE * (ballNumber - 1)) { mPaint.setAlpha(0); } if (angle > BALLS_DISTANCE * (ballNumber - 1)) { isShow = false; } } canvas.drawCircle(x, y, ballRadius, mPaint); } handler.sendEmptyMessageDelayed(MSG_BALL_VISIBLE, 15); //旋转快慢 合适自己调整 } /** * 小球颜色 * * @param ballColor */ public void setBallColor(int ballColor) { this.ballColor = ballColor; if (mPaint != null) { mPaint.setColor(ballColor); } } /** * 小球的数量 * * @param ballNumber */ public void setBallNumber(int ballNumber) { this.ballNumber = ballNumber; }}
分享给大家github地址
3 0
- Android自定义View基础篇(二)
- Android 自定义view基础(二)
- Android 自定义View基础(二)
- android自定义View基础系列二(贝塞尔曲线)
- Android自定义View基础篇(一)
- android自定义View(二)
- Android自定义View(二)
- android 自定义view(二)
- Android自定义View(二)
- Android自定义View(二)
- Android 自定义View(二)
- Android 自定义View(二)
- Android 自定义View(基础)
- android 自定义view(二),继承view
- Android 自定义View (二)
- Android 自定义View (二)
- Android 自定义View (二)
- Android 自定义View (二)
- 创建对象的内存图解
- sql server2008 “不允许保存更改,,,”
- Android开发中用到的第三方框架汇总
- MYSQL开启慢查询日志实施
- 数据结构的学习一简单排序算法1
- Android自定义View基础篇(二)
- RecyclerView简单使用
- 在中国知网下载 PDF 格式的学位论文
- 网络 应用层协议
- 【盘点】2014年跨境进口型电商十大模式
- mysql服务器查询慢原因分析与解决方法小结
- hdoj 2018 母牛的故事 (递归)
- CodeForces 320BPing-Pong (Easy Version)-DFS
- BZOJ_P2460 [BeiJing2011]元素(贪心+线性基)