SleepCartogramView.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.careeach.sport.R;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* 睡眠条形图
*/
public class SleepCartogramView extends View {
private int height;
private int width;
private Paint timeTextPaint;
private float minuteWidth;
private float contentEndY;
//ATTR
// private float attrSpacing;
private int attrTextColor;
private int attrBodyColor;
private int attrXLineColor;
private int attrChooseColor;
private float attrTextSize;
private float attrTextMarginTop;
private float attrTextMarginBottom;
private float attrPaddingTop;
private float attrXLineHeight;
private Paint stripePaint;
private Paint xLinePaint;
private Paint bodyBGPaint;
private List<Long[]> values;
private String beginTimeLabel;
private String endTimeLabel;
private float touchX = 0;
private OnSelectedChanged onSelectedChanged;
private ViewGroup parentViewGroup;
public SleepCartogramView(Context context) {super(context);
}
public SleepCartogramView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);
init(context, attrs);
}
public SleepCartogramView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
init(context, attrs);
}
public SleepCartogramView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SleepCartogramView);
attrTextColor = typedArray.getColor(R.styleable.SleepCartogramView_sc_textColor, Color.GRAY);
attrBodyColor = typedArray.getColor(R.styleable.SleepCartogramView_sc_bodyColor, Color.GRAY);
attrXLineColor = typedArray.getColor(R.styleable.SleepCartogramView_sc_xLineColor, Color.GRAY);
attrChooseColor = typedArray.getColor(R.styleable.SleepCartogramView_sc_chooseColor, Color.WHITE);
attrTextSize = typedArray.getDimension(R.styleable.SleepCartogramView_sc_textSize, 10);
attrTextMarginTop = typedArray.getDimension(R.styleable.SleepCartogramView_sc_textMarginTop, 10);
attrTextMarginBottom = typedArray.getDimension(R.styleable.SleepCartogramView_sc_textMarginBottom, 10);
attrPaddingTop = typedArray.getDimension(R.styleable.SleepCartogramView_sc_paddingTop, 10);
attrXLineHeight = typedArray.getDimension(R.styleable.SleepCartogramView_sc_xLineHeight, 1);
typedArray.recycle();
timeTextPaint = new Paint();
timeTextPaint.setTextSize(attrTextSize);
timeTextPaint.setColor(attrTextColor);
stripePaint = new Paint();
stripePaint.setAntiAlias(true);
stripePaint.setStyle(Paint.Style.FILL);
xLinePaint = new Paint();
xLinePaint.setColor(attrXLineColor);
xLinePaint.setStrokeWidth(attrXLineHeight);
bodyBGPaint = new Paint();
bodyBGPaint.setColor(attrBodyColor);
bodyBGPaint.setAntiAlias(true);
bodyBGPaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
contentEndY = height - attrTextMarginBottom - attrTextMarginTop - measureTextHeight(timeTextPaint);
}
@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);
canvas.drawRect(0, 0, width, contentEndY, bodyBGPaint);
if (values != null && values.size() > 0) {for (int i = 0; i < values.size(); i++) {Long[] valueArray = values.get(i);
long beginTime = valueArray[0];
long endTime = valueArray[1];
int color = valueArray[2].intValue();
float left = ((beginTime - values.get(0)[0]) / 60000) * minuteWidth;
float top = attrPaddingTop;
float right = ((endTime - values.get(0)[0]) / 60000) * minuteWidth;
float bottom = contentEndY;
if ((touchX == 0 && i == 0) || (touchX >= left && touchX <= right)) {stripePaint.setColor(attrChooseColor);
if (onSelectedChanged != null) {onSelectedChanged.onChanged(i);
}
} else {stripePaint.setColor(color);
}
canvas.drawRect(left, top, right, bottom, stripePaint);
}
}
canvas.drawLine(0, contentEndY + attrXLineHeight, width, contentEndY + attrXLineHeight, xLinePaint);
if (beginTimeLabel != null && beginTimeLabel.length() > 0) {canvas.drawText(beginTimeLabel, 0, height - attrTextMarginBottom, timeTextPaint);
}
if (endTimeLabel != null && endTimeLabel.length() > 0) {canvas.drawText(endTimeLabel, width - timeTextPaint.measureText(endTimeLabel), height - attrTextMarginBottom, timeTextPaint);
}
}
private String dateFormat(Date date, String pattern) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
return simpleDateFormat.format(date);
}
public void setValues(List<Long[]> values) {if (values != null && values.size() > 0) {beginTimeLabel = dateFormat(new Date(values.get(0)[0]), "HH:mm");
endTimeLabel = dateFormat(new Date(values.get(values.size() - 1)[1]), "HH:mm");
long unitMinute = (values.get(values.size() - 1)[1] - values.get(0)[0]) / 60000;
minuteWidth = (float) width / (float) unitMinute;
} else {
beginTimeLabel = "00:00";
endTimeLabel = "08:00";
minuteWidth = 0;
}
this.values = values;
touchX = 0;
postInvalidate();}
private int dip2px(float dpValue) {final float scale = getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 测量文字的高度
**/
public static float measureTextHeight(Paint paint) {
float height = 0f;
if (null == paint) {return height;}
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
height = fontMetrics.descent - fontMetrics.ascent;
return height;
}
@Override
public boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX = event.getX();
if (parentViewGroup != null) {parentViewGroup.requestDisallowInterceptTouchEvent(true);
}
postInvalidate();
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(event.getX() - touchX) > 1) {touchX = event.getX();
postInvalidate();}
break;
case MotionEvent.ACTION_UP:
touchX = event.getX();
postInvalidate();
if (parentViewGroup != null) {parentViewGroup.requestDisallowInterceptTouchEvent(false);
}
break;
}
return true;
}
public interface OnSelectedChanged {void onChanged(int position);
}
public void setParentViewGroup(ViewGroup parentViewGroup) {this.parentViewGroup = parentViewGroup;}
public OnSelectedChanged getOnSelectedChanged() {return onSelectedChanged;}
public void setOnSelectedChanged(OnSelectedChanged onSelectedChanged) {this.onSelectedChanged = onSelectedChanged;}
}
attrs.xml 增加属性
<declare-styleable name="SleepCartogramView">
<attr name="sc_textColor" format="color" />
<attr name="sc_textSize" format="dimension" />
<attr name="sc_spacing" format="dimension" />
<attr name="sc_xLineColor" format="color" />
<attr name="sc_xLineHeight" format="dimension" />
<attr name="sc_bodyColor" format="color" />
<attr name="sc_chooseColor" format="color" />
<attr name="sc_textMarginTop" format="dimension" />
<attr name="sc_textMarginBottom" format="dimension" />
<attr name="sc_paddingTop" format="dimension" />
</declare-styleable>
应用
<xxx.SleepCartogramView
android:id="@+id/sc_statis"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@android:color/white"
app:sc_bodyColor="#f5f5f5"
app:sc_chooseColor="#dfdfdf"
app:sc_paddingTop="0dp"
app:sc_spacing="3dp"
app:sc_textColor="@android:color/darker_gray"
app:sc_textMarginBottom="15dp"
app:sc_textMarginTop="5dp"
app:sc_textSize="@dimen/font_remark"
app:sc_xLineColor="@color/bg_line"
app:sc_xLineHeight="0.5dp" />
/**
* 设置值
* @param values
* array[0] 开始工夫
* array[1] 完结工夫
* array[2] 色彩值
*/
void setValues(List<Long[]> values)
void setParentViewGroup(ViewGroup parentViewGroup)
/**
* 增加选中监听
*/
scStatis.setOnSelectedChanged(new SleepCartogramView.OnSelectedChanged() {
@Override
public void onChanged(int position) {}});