android自定义view,一直一知半解的,项目中用到的时候,直接是拿来主义,照着需求改改。
趁着项目空闲,自己写下,加深下印象
效果
自定义view中的三个构造调用时机
- 一个参数的,
View view = new View(context);
这样的场景会调用 - 两个参数的,在
layout.xml
布局文件中设置自定义view的时候会调用 - 三个参数的,在布局文件中设置定义view的时候,对
style
属性进行了设置的时候会调用。
自定义view绘制过程
- measure,可以复写
onMeasure
方法,可以理解为计算这个view需要的大小 - layout,可以复写
onLayout
方法,可以理解为这个view放在屏幕具体的位置 - draw,可以复写
onDraw
方法,理解为这个自定义view,具体内容展示的绘制
代码部分
自定义的属性文件attrs.xml
,应该是在/res/values
目录下
需要关注的
-
declare-styleable name
和attr name
通过这两个属性,可以在自定义view中通过TypedArray
获取到布局xml文件配置的值,
后面的代码可以看到
布局文件中xml中对自定义view的配置
需要关注的
- 使用
app:xxx
的属性配置前,需要在xml的xmlns
声明一下
例:xmlns:app="http://schemas.android.com/apk/res-auto"
- 属性值设置
app:loading_color
默认的颜色
app:loading_height
高度
app:loading_space
间隔距离
app:loading_ypos
y坐标
自定义view的实现代码
package nico.customviewapp;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2016/10/26.
*/
public class LoadingView extends View {
private float mLoading_Space = 0;
private float mLoading_Height = 0;
private int mLoading_color = 0;
private float default_mLoading_Space = 10.0f;
private float default_mLoading_Height = 5.0f;
private int mdefault_mLoading_color = 0x1E90FF;
private float default_mLoading_YPos = 100.0f;
//默认分成5段
private int mSum = 5;
private int mPerSize = 0;
private Paint mPaint;
private int mScreenWidth = 0;
private int mYPos = 100;
private int mTime = 0;
private List mLineList = new ArrayList<>();
public LoadingView(Context context) {
super(context);
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
initSize(context, attrs);
}
public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initSize(context, attrs);
}
private void initSize(Context context, AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.LoadingView);
mLoading_Height = typedArray.getDimension(R.styleable.LoadingView_loading_height, default_mLoading_Height);
mLoading_Space = typedArray.getDimension(R.styleable.LoadingView_loading_space, default_mLoading_Space);
mLoading_color = typedArray.getColor(R.styleable.LoadingView_loading_color, mdefault_mLoading_color);
mYPos = (int) typedArray.getDimension(R.styleable.LoadingView_loading_ypos, default_mLoading_YPos);
mPaint = new Paint();
mPaint.setColor(mLoading_color);
mPaint.setStrokeWidth((float) mLoading_Height);
mPerSize = getPerWidth(getScreenWidth(context), mLoading_Space);
initLineList();
}
private int getScreenWidth(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
display.getMetrics(metrics);
mScreenWidth = metrics.widthPixels;
return mScreenWidth;
}
private int getPerWidth(int screenWidth, float spaceWidth) {
//默认分成5段
int perWidth = (int) ((screenWidth - (spaceWidth * (mSum))) / mSum);
return perWidth;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
initview(canvas, 5);
postInvalidate();
}
public class LineEntity {
private int startX;
private int endX;
private int color;
private int leftStartX;
public int getStartX() {
return startX;
}
public void setStartX(int startX) {
this.startX = startX;
}
public int getEndX() {
return endX;
}
public void setEndX(int endX) {
this.endX = endX;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getLeftStartX() {
return leftStartX;
}
public void setLeftStartX(int leftStartX) {
this.leftStartX = leftStartX;
}
}
private void initLineList() {
for (int i = 0; i < mSum; i++) {
LineEntity line = new LineEntity();
int x1 = (int) (i * (mLoading_Space + mPerSize));
int x2 = (int) ((i * (mLoading_Space + mPerSize)) + mPerSize);
line.setStartX(x1);
line.setEndX(x2);
switch (i) {
case 0:
line.setColor(mLoading_color);
break;
case 1:
line.setColor(Color.GRAY);
break;
case 2:
line.setColor(Color.YELLOW);
break;
case 3:
line.setColor(Color.RED);
break;
case 4:
line.setColor(Color.GREEN);
break;
default:
line.setColor(mLoading_color);
break;
}
mLineList.add(line);
}
}
/**
*
* @param canvas
* @param moveX 位移单位,通过大小的调整,可以实现速度的调节
*/
private void initview(Canvas canvas, int moveX) {
for (int i = 0; i < mLineList.size(); i++) {
LineEntity ll = mLineList.get(i);
mPaint.setColor(ll.getColor());
int startX = ll.getStartX();
if (startX + moveX <= (mScreenWidth * (mSum - 1) / mSum)) {
startX = startX + moveX;
ll.setStartX(startX);
canvas.drawLine(ll.getStartX(), mYPos, ll.getStartX() + mPerSize, mYPos, mPaint);
mPaint.setColor(Color.WHITE);
canvas.drawLine(ll.getStartX() + mPerSize, mYPos, ll.getStartX() + mPerSize + mLoading_Space, mYPos, mPaint);
} else {
if (startX + moveX < mScreenWidth) {
ll.setStartX(startX + moveX);
//剩余的区域
int left = mScreenWidth - startX - moveX;
if (mPerSize > left) {
//只画色值的
canvas.drawLine(ll.getStartX(), mYPos, mScreenWidth, mYPos, mPaint);
//最左边出来的 色值以及 间隔区域
int leftvalue = mPerSize - left;
canvas.drawLine(0, mYPos, leftvalue, mYPos, mPaint);
mPaint.setColor(Color.WHITE);
canvas.drawLine(leftvalue, mYPos, leftvalue + mLoading_Space, mYPos, mPaint);
} else {
//都画
canvas.drawLine(startX + moveX, mYPos, startX + moveX + mPerSize, mYPos, mPaint);
//最右边的 间隔区域
mPaint.setColor(Color.WHITE);
canvas.drawLine(startX + moveX + mPerSize, mYPos, mScreenWidth, mYPos, mPaint);
//最左边可能的 间隔区域
int leftblank = (int) (mLoading_Space - (left - mPerSize));
if (leftblank > 0) {
canvas.drawLine(0, mYPos, leftblank, mYPos, mPaint);
}
}
} else {
//置0
startX = 0;
ll.setStartX(startX);
canvas.drawLine(ll.getStartX(), mYPos, ll.getStartX() + mPerSize, mYPos, mPaint);
}
}
}
}
}
参考的这位仁兄的文章哈。。http://www.jianshu.com/p/84cee705b0d3