android自定义控件实现简易时间轴(1)
作者:哈哈哈哈哈哈_Y 时间:2022-09-24 00:42:23
本文实例为大家分享了android自定义控件实现简易时间轴的具体代码,供大家参考,具体内容如下
之前项目需要写一个消费记录,类似于时间轴似的控件,自身在自定义控件这里不咋地(…),最后搞了一个这个demo
效果图:
这里就是绘制圆和上下两条线
1.资源文件,定义一些基本的属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="textSize" format="dimension" />
<attr name="textColor" format="color" />
<attr name="textTitle" format="string" />
<attr name="borderColor" format="color" />
<attr name="borderWidth" format="dimension" />
<attr name="lineColor" format="color" />
<attr name="lineWidth" format="dimension" />
<attr name="bgColor" format="color" />
<attr name="mRadius" format="dimension"/>
<declare-styleable name="CustomCicleView">
<attr name="textSize" />
<attr name="textColor" />
<attr name="textTitle" />
<attr name="lineColor" />
<attr name="lineWidth" />
<attr name="bgColor" />
<attr name="borderColor" />
<attr name="borderWidth" />
<attr name="mRadius" />
</declare-styleable>
</resources>
2.获取属性:
int attr=a.getIndex(i);
switch (attr) {
case R.styleable.CustomCicleView_textSize:
// 默认设置为16sp,TypeValue也可以把sp转化为px
mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 14, getResources().getDisplayMetrics()));
break;
case R.styleable.CustomCicleView_textColor:
mTextColor=a.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomCicleView_lineWidth:
mLineWidth= a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics()));
break;
case R.styleable.CustomCicleView_lineColor:
mLineColor=a.getColor(attr, lineColr);
break;
case R.styleable.CustomCicleView_borderWidth:
mBorderWidth= a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics()));
break;
case R.styleable.CustomCicleView_borderColor:
mBorderColor=a.getColor(attr, borderColor);
break;
case R.styleable.CustomCicleView_bgColor:
mBgColor=a.getColor(attr, bgColor);
break;
}
这里主要释放资源方便回收:
a.recycle();
//官方API的解释是:给回一个先前的提取的数组,为以后复用,,就是当前的对象回收,下次要用的时候就不用重新再new一个新的对象了,直接从它的回收池里面拿就行。
public void recycle ():
Give back a previously retrieved array, for later re-use
3.重要绘制代码:
super.onDraw(canvas);
int centre = getWidth() / 2; // 获取圆心的x坐标
//半径比较
int mixWidth=getMeasuredWidth()>getMeasuredHeight()?getMeasuredHeight():getMeasuredWidth();
mRadius =mRadius>(mixWidth)?(mixWidth):mRadius;
mBorderWidth =mRadius/2>=(mBorderWidth)?(mBorderWidth):mRadius/10;//最终的效果要不是自己设置的要不就是半径的1/5
int radius = mRadius/2 - mBorderWidth / 2;// 半径
mLineHeight=Math.abs(getHeight()/2-radius);//这个地方要判断设置正负
if(lineLocation!=-1){
drawLine(canvas,centre);
}
//绘制背景
bgPaint.setColor(Color.parseColor("#00000000"));
bgPaint.setTextSize(mTextSize);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), bgPaint);
//绘制圆
bgPaint.setAntiAlias(true); // 消除锯齿
bgPaint.setColor(mBgColor);
bgPaint.setStyle(Paint.Style.FILL); // 设置实心
canvas.drawCircle(centre, centre, radius, bgPaint);
//绘制圆环
borderPaint.setStrokeWidth(mBorderWidth); // 设置圆环的宽度
borderPaint.setAntiAlias(true); // 消除锯齿
if (mBorderColor != 0) {
borderPaint.setColor(mBorderColor);
} else {
borderPaint.setColor(borderColor);
}
borderPaint.setStyle(Paint.Style.STROKE); // 设置实心
canvas.drawCircle(centre,centre, radius - mBorderWidth / 2+mLineWidth/2, borderPaint);
//绘制文本
bgPaint.setColor(mTextColor);
textPaint.getTextBounds(mTextTitle, 0, mTextTitle.length(), textRect);
canvas.drawText(mTextTitle, centre -textRect.width()/2, centre + textRect.height() / 2, bgPaint);
这里给了一个int值来判断当前需要绘制那个位置的line;值是0只需绘制 上方line,值是 1只需绘制下方line,值是2同事绘制上下方line,值是-1不需绘制line;这个值由用户使用的时候传递过来这样就可以绘制对应的line
//0 上方 1 下方 2 上下两个
private void drawLine(Canvas canvas, float centre) {
linePaint.setColor(borderColor);
linePaint.setStrokeWidth(mLineWidth);
if (lineLocation == 0) {
// canvas.drawLine(centre, 0.5F*centre-mLineHeight, centre, centre, linePaint);
canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint);
} else if (lineLocation == 1) {
canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint);
} else if (lineLocation == 2) {
// canvas.drawLine(centre, mRadius * 0.5F - mLineHeight-mBorderWidth, centre, mLineHeight, linePaint);
canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint);
canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint);
}
}
4.使用
这里的使用有两种,一种是在xml中直接布局,设置属性,一种是在代码中初始化然后根据提供的set方法来设置相应的属性。
在你布局中使用的时候要加上
xmlns:app=”http://schemas.android.com/apk/res/com.example.circleview”
com.example.circleview:是包名
这样你就可以设置这个控件的属性了
<com.example.circleview.CircleImg
android:id="@+id/itemImg"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="2dp"
app:bgColor="#f88"
app:borderColor="#138ddd"
app:textColor="#fff"
app:textSize="12dp" />
最终效果:
基本的一个圆就好了,现在来实现开始的时候的效果图,基本就是用listView实现:
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.example.circleview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:orientation="vertical"
tools:context="com.example.circleview.MainActivity" >
<ListView
android:id="@+id/listView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="#00000000"
android:dividerHeight="0dp"
>
</ListView>
</LinearLayout>
MainActivity.java:
public class MainActivity extends Activity {
private List<String> list=new ArrayList<String>();
ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
listView=(ListView) findViewById(R.id.listView);
listView.setAdapter(new TimeLineAdapter(list, this));
}
private void initData() {
for (int i =11; i >1; i--) {//时间从小到大
list.add("05/"+i);
}
}
}
Adapter:
public class TimeLineAdapter extends BaseAdapter {
private static final int[] COLOR = new int[] {
0xff33b5e5, 0xffaa66cc, 0xff99cc00, 0xffffbb33, 0xffff4444,0xff009933,0xffff9988, 0xffffddcc,0xff00ffff,0xffffff00
};
private List<String> list;
private Context context;
private ViewHolder holder;
public TimeLineAdapter(List<String> list, Context context) {
super();
this.list = list;
this.context = context;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int type = getItemViewType(position);
if(convertView==null){
convertView=View.inflate(context, R.layout.item,null);
holder=new ViewHolder();
convertView.setTag(holder);
holder.img=(CircleImg) convertView.findViewById(R.id.itemImg);
holder.item=(TextView) convertView.findViewById(R.id.itemText);
}else{
holder=(ViewHolder) convertView.getTag();
}
holder.img.setBgAndBorderColor(COLOR[position%10]);
holder.img.invalidate();//记得重绘
holder.img.setLineLocation(type);
holder.img.setmTextTitle(list.get(position));
holder.item.setText("哈哈哈哈哈哈哈哈");
return convertView;
}
@Override
public int getItemViewType(int position) {
final int size = list.size() - 1;
if (size == 0)
return ItemType. * ;
else if (position == 0)
return ItemType.FOOTER;
else if (position == size)
return ItemType.HEADER;
else return ItemType.NORMAL;
}
class ViewHolder{
TextView item;
CircleImg img;
}
}
这里绘制上下line的时候是通过getItemViewType()返回的view id值来判断的,ItemType中有四个变量:
public final static int NORMAL = 2; //表示绘制上下方
public final static int HEADER = 0; //表示绘制下方
public final static int FOOTER = 1; //表示绘制上方
public final static int * = -1; //表示不绘制
然后通过holder.img.setLineLocation(type);来设置当前绘制的line。
CIcleVIew.java下:
/**
* Created by yqy on 2016/11/28.
*/
public class CircleImg extends View {
//画笔
private Paint bgPaint, linePaint, borderPaint,textPaint;
private Rect bgRect, textRect;
//基本属性
private int mTextSize;
private int mTextColor;
private String mTextTitle;
private int lineColr = Color.parseColor("#AAAAAA");
private int borderColor = Color.parseColor("#AAAAAA");
private int bgColor = Color.parseColor("#138DDD");
private int mBorderColor;
private int mBorderWidth = 2;
private int mLineColor;
private int mLineWidth = 2;
private int mLineHeight;
private int mBgColor;
//line绘制
private int lineLocation = -1;//0 上方 1 下方 2 上下两个
private int mRadius = 40;
public CircleImg(Context context) {
this(context, null);
}
//设置line的位置 0 上方 1 下方 2 上下两个
public void setLineLocation(int lineLocation) {
this.lineLocation = lineLocation;
}
//设置纯色的整圆形,包括背景
public void setBgAndBooderCOlor(int color) {
this.mBorderColor = color;
this.mBgColor = color;
}
public void setmTextTitle(String mTextTitle) {
this.mTextTitle = mTextTitle;
}
public void setmRadius(int mRadius) {
this.mRadius = mRadius;
}
public CircleImg(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public CircleImg(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCicleView, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.CustomCicleView_textSize:
// 默认设置为16sp,TypeValue也可以把sp转化为px
mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 14, getResources().getDisplayMetrics()));
break;
case R.styleable.CustomCicleView_textColor:
mTextColor = a.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomCicleView_textTitle:
mTextTitle = a.getString(attr);
break;
case R.styleable.CustomCicleView_lineWidth:
mLineWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics()));
break;
case R.styleable.CustomCicleView_lineColor:
mLineColor = a.getColor(attr, lineColr);
break;
case R.styleable.CustomCicleView_mRadius:
mRadius=a.getInt(attr,40);
break;
case R.styleable.CustomCicleView_borderWidth:
mBorderWidth = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, 2, getResources().getDisplayMetrics()));
break;
case R.styleable.CustomCicleView_borderColor:
mBorderColor = a.getColor(attr, borderColor);
break;
case R.styleable.CustomCicleView_bgColor:
mBgColor = a.getColor(attr, bgColor);
break;
}
}
a.recycle();
bgPaint = new Paint();
borderPaint = new Paint();
linePaint = new Paint();
textPaint = new Paint();
textRect = new Rect();
textPaint.setTextSize(mTextSize);
}
//暂时不计算
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int w = getPaddingLeft() + getPaddingRight();
int h = getPaddingTop() + getPaddingBottom();
if (bgPaint != null) {
w += mRadius;
h += mRadius;
}
w = Math.max(w, getMeasuredWidth());
h = Math.max(h, getMeasuredHeight());
int widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
int heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int centre = getWidth() / 2; // 获取圆心的x坐标
int radius = mRadius - mBorderWidth / 2;// 半径
mLineHeight=getHeight()/2-radius;//这个地方要判断设置正负
if(lineLocation!=-1){
drawLine(canvas,centre);
}
//绘制背景
bgPaint.setColor(Color.parseColor("#00000000"));
bgPaint.setTextSize(mTextSize);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), bgPaint);
//绘制圆
bgPaint.setAntiAlias(true); // 消除锯齿
bgPaint.setColor(mBgColor);
bgPaint.setStyle(Paint.Style.FILL); // 设置实心
canvas.drawCircle(centre, centre, radius, bgPaint);
//绘制圆环
borderPaint.setStrokeWidth(mBorderWidth); // 设置圆环的宽度
borderPaint.setAntiAlias(true); // 消除锯齿
if (mBorderColor != 0) {
borderPaint.setColor(mBorderColor);
} else {
borderPaint.setColor(borderColor);
}
borderPaint.setStyle(Paint.Style.STROKE); // 设置实心
canvas.drawCircle(centre,centre, radius - mBorderWidth / 2+mLineWidth/2, borderPaint);
//绘制文本
bgPaint.setColor(mTextColor);
textPaint.getTextBounds(mTextTitle, 0, mTextTitle.length(), textRect);
canvas.drawText(mTextTitle, centre -textRect.width()/2, centre + textRect.height() / 2, bgPaint);
}
//0 上方 1 下方 2 上下两个
private void drawLine(Canvas canvas, float centre) {
linePaint.setColor(borderColor);
linePaint.setStrokeWidth(mLineWidth);
if (lineLocation == 0) {
canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint);
} else if (lineLocation == 1) {
canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint);
} else if (lineLocation == 2) {
canvas.drawLine(centre, 0, centre, mLineHeight*2, linePaint);
canvas.drawLine(centre, centre, centre, centre * 2F + mLineHeight, linePaint);
}
}
}
styleable.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="textSize" format="dimension" />
<attr name="textColor" format="color" />
<attr name="textTitle" format="string" />
<attr name="borderColor" format="color" />
<attr name="borderWidth" format="dimension" />
<attr name="lineColor" format="color" />
<attr name="lineWidth" format="dimension" />
<attr name="bgColor" format="color" />
<attr name="mRadius" format="dimension"/>
<declare-styleable name="CustomCicleView">
<attr name="textSize" />
<attr name="textColor" />
<attr name="textTitle" />
<attr name="lineColor" />
<attr name="lineWidth" />
<attr name="bgColor" />
<attr name="borderColor" />
<attr name="borderWidth" />
<attr name="mRadius" />
</declare-styleable>
</resources>
简易时间轴二
来源:https://blog.csdn.net/u010904027/article/details/51669702