上一篇Android RecycleView(三) 完成了点击事件 这次使用recycleview完成一个有意思的时光轴效果。
效果图:
要实现次效果呢 其实就是我们在每一个item中画一个圆圈加一个线的图形
第一种和第二种都可以实现,当然我们可以找美工给我们相应的图片,放入item中,今天我们不说图片,自己画出第一个,第二个原理一样,只是画的坐标不一样。
自定义的 图形:
package com.chs.myrecycleview.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import com.chs.myrecycleview.R;
/**
* 作者:chs on 2016/2/4 10:02
* 邮箱:657083984@qq.com
*/
public class TimeLine extends View {
public static final int START = 0;
public static final int END = 1;
public static final int NORMAL = 2;
public static final int SPECIAL = 3;//只有一条数据的时候
private int mIconSize;
private int mLineSize;
private Drawable mBeginLine;
private Drawable mEndLine;
private Drawable mIcon;
public TimeLine(Context context) {
this(context, null);
}
public TimeLine(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TimeLine(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.TimeLine);
this.mBeginLine = array.getDrawable(R.styleable.TimeLine_begin_line);
this.mEndLine = array.getDrawable(R.styleable.TimeLine_end_line);
this.mIcon = array.getDrawable(R.styleable.TimeLine_my_icon);
this.mIconSize = array.getDimensionPixelSize(R.styleable.TimeLine_my_icon_size,20);
this.mLineSize = array.getDimensionPixelSize(R.styleable.TimeLine_line_size,2);
array.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int w = mIconSize+getPaddingRight()+getPaddingLeft();
int h = mIconSize+getPaddingTop() +getPaddingBottom();
int widthSize = resolveSizeAndState(w,widthMeasureSpec,0);
int heightSize = resolveSizeAndState(h,heightMeasureSpec,0);
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//当view显示的时候调用此方法
initDrawable();
}
private void initDrawable() {
int left = getPaddingLeft();
int right = getPaddingRight();
int top = getPaddingTop();
int bottom = getPaddingBottom();
int width = getWidth();
int height = getHeight();
int cWidth = width-left-right;
int cHeight = height-top-bottom;
int iconSize = Math.min(mIconSize,Math.min(cWidth,cHeight));
Rect bounds = null;
if(mIcon!=null){
mIcon.setBounds(left,top,left+iconSize,top+iconSize);
bounds = mIcon.getBounds();
}
int lineLeft = bounds.centerX() - mLineSize/2;//除以2
if(mBeginLine!=null){
mBeginLine.setBounds(lineLeft,0,lineLeft+mLineSize,bounds.top);
}
if(mEndLine!=null){
mEndLine.setBounds(lineLeft,bounds.bottom,lineLeft+mLineSize,height);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// if(mBeginLine!=null){
// mBeginLine.draw(canvas);
// }
if(mEndLine!=null){
mEndLine.draw(canvas);
}
if(mIcon!=null){
mIcon.draw(canvas);
}
}
public void setIconSize(int mIconSize) {
this.mIconSize = mIconSize;
initDrawable();
invalidate();
}
public void setLineSize(int mLineSize) {
this.mLineSize = mLineSize;
initDrawable();
invalidate();
}
public void setBeginLine(Drawable mBeginLine) {
this.mBeginLine = mBeginLine;
initDrawable();
invalidate();
}
public void setEndLine(Drawable mEndLine) {
this.mEndLine = mEndLine;
initDrawable();
invalidate();
}
public void setIcon(Drawable mIcon) {
this.mIcon = mIcon;
initDrawable();
invalidate();
}
}
item中:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myApp="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="@+id/ll_main"
>
<com.chs.myrecycleview.widget.TimeLine
android:id="@+id/time_line"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
myApp:my_icon="@drawable/cicle"
myApp:my_icon_size="25dp"
myApp:begin_line="@drawable/line"
myApp:end_line="@drawable/line"
myApp:line_size="3dp"
/>
<TextView
android:id="@+id/tv_text"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:textSize="20sp"
android:text="hahah"
/>
</LinearLayout>
自定义属性 :定义圆和线的宽高:这里是按照上面图二中写的 分了3部分 画的时候没用到beginline
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TimeLine">
<attr name="begin_line" format="color|reference"/>
<attr name="end_line" format="color|reference"/>
<attr name="line_size" format="dimension"/>
<attr name="my_icon_size" format="dimension"/>
<attr name="my_icon" format="color|reference"/>
</declare-styleable>
</resources>
在drawable中定义两个shape 一个圆形 一个方形
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorPrimary" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/colorPrimary" />
</shape>
更新一下现在用的新的 。因为我发现这个东西就一个圆圈两个线条 根本不用绘制图片 直接canvas画就好了 然后重新写了一个 不需要再写shape 和自定义属性:
package com.hsm.bxt.widgets;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import com.hsm.bxt.utils.DensityUtil;
/**
* 作者:chs on 2016/10/21 10:56
* 邮箱:657083984@qq.com
*/
public class PatrolPointMarker extends View {
private Paint mCirclePaint, mLinePaint,mTextPaint;
private int mCircleColor = Color.parseColor("#C4D4E8");
private int mLineColor = Color.parseColor("#C4D4E8");
private int mTextColor = Color.parseColor("#ffffff");
private int mRadius = 36;
private int mToLineHeight;
private int mLineHeight;
private String mText = "001";
private boolean mIsDrawTopLine = true;
private boolean mIsDrawBottomLine = true;
public PatrolPointMarker(Context context) {
super(context);
init(context);
}
public PatrolPointMarker(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PatrolPointMarker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
int mWidth = context.getResources().getDisplayMetrics().widthPixels;
mRadius = (int)mWidth/30;
mToLineHeight = DensityUtil.dip2px(context,5);
int strokeWidth = DensityUtil.dip2px(context, 2);
int textSize = DensityUtil.dip2px(context, 10);
mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(mCircleColor);
mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
mLinePaint.setStrokeWidth(strokeWidth);
mLinePaint.setColor(mLineColor);
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(mTextColor);
mTextPaint.setTextSize(textSize);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = mRadius*2;
int desiredHeight = getPaddingBottom()+getPaddingTop();
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
//计算宽度
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
width = Math.min(desiredWidth, widthSize);
} else {
width = desiredWidth;
}
//计算高度
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
height = Math.min(desiredHeight, heightSize);
} else {
height = desiredHeight;
}
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mLineHeight = h-mRadius*2;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mIsDrawTopLine){
canvas.drawLine(mRadius,0,mRadius,mToLineHeight,mLinePaint);
}
canvas.drawCircle(mRadius,mRadius+mToLineHeight,mRadius,mCirclePaint);
if(mIsDrawBottomLine){
canvas.drawLine(mRadius,mRadius*2+mToLineHeight,mRadius,mRadius*2+mToLineHeight+mLineHeight,mLinePaint);
}
Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();
int baseline = (mRadius*2+mToLineHeight*2 - fontMetrics.bottom - fontMetrics.top) / 2;
canvas.drawText(mText,mRadius-mTextPaint.measureText(mText)/2,baseline,mTextPaint);
}
public void setText(String text){
this.mText = text;
invalidate();
}
public void setDrawTopLine(boolean drawTopLine){
this.mIsDrawTopLine = drawTopLine;
}
public void setDrawBottomLine(boolean drawBottomLine){
this.mIsDrawBottomLine = drawBottomLine;
}
public void setCircleColor(int color){
mCirclePaint.setColor(color);
invalidate();
}
public void setLineColor(int color){
mLinePaint.setColor(color);
invalidate();
}
}
package com.hsm.bxt.utils;
import android.content.Context;
public class DensityUtil {
/**
*
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
*
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
}
就一百多行代码 非常轻量,用起来更方便。