StripeStaticsView.java
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.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.util.List;
/**
* 条形统计图
*/
public class StripeStaticsView extends View {
private List<Integer> values;
private List<String> titles;
private int height;
private int width;
private Paint stripePaint;
private Paint stripeSelectedPaint; // 选中状态
private Paint titleTextPaint; // 标题字
private Paint bodyBackGroundPaint;
private Paint titleBackGroundPaint;
private float itemHeight; // 一个值对于高度
//ATTR
private int itemColor; // 条形颜色
private float itemWidth; // 条形宽度
private float itemSpaceWidth; // 条形间隙
private int itemSelectColor;
private int maxValue;
private float centerX;
private float startX; // 第一条条形起始X座标
private float moveWidth = 0f;
private float touchStarX = 0;
private float titleHeight; // 标题高度
private float titleTextY; // 标题Y坐标
private float titleTextSize; // 标题字体大小
private float titleTextLineSpace; // 标题行间隙
private int titleTextColor; // 标题字颜色
private int titleTextSelectColor; // 标题字颜色
private int bodyBackGroundColor; // 主背景
private int titleBackGroundColor; // 标题背景
private boolean isMove = false;
private boolean isUp = false;
private OnStripeStaticsListener onStripeStaticsListener;
private int selectPosition = -1;
private TouchEventCountThread touchEventCountThread;
private final int HANDLER_WHAT_CLICK = 1;
private final int HANDLER_WHAT_SELECT_CHANGE = 2;
private ViewGroup parentViewGroup;
public StripeStaticsView(Context context) {
super(context);
}
public StripeStaticsView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public StripeStaticsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
public StripeStaticsView(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.StripeStaticsView);
itemColor = typedArray.getColor(R.styleable.StripeStaticsView_itemColor, Color.BLACK);
itemSelectColor = typedArray.getColor(R.styleable.StripeStaticsView_itemSelectColor, Color.WHITE);
itemSpaceWidth = typedArray.getDimension(R.styleable.StripeStaticsView_itemSpaceWidth, Color.BLACK);
itemWidth = typedArray.getDimension(R.styleable.StripeStaticsView_itemWidth, dip2px(20));
maxValue = typedArray.getInt(R.styleable.StripeStaticsView_maxValue, 100);
titleTextSize = typedArray.getDimension(R.styleable.StripeStaticsView_titleTextSize, sp2px(12));
titleTextLineSpace = typedArray.getDimension(R.styleable.StripeStaticsView_titleTextLineSpace, dip2px(10));
titleTextColor = typedArray.getColor(R.styleable.StripeStaticsView_titleTextColor, Color.WHITE);
titleTextSelectColor = typedArray.getColor(R.styleable.StripeStaticsView_titleTextSelectColor, Color.WHITE);
bodyBackGroundColor = typedArray.getColor(R.styleable.StripeStaticsView_contentBGColor, Color.WHITE);
titleBackGroundColor = typedArray.getColor(R.styleable.StripeStaticsView_titleBGColor, Color.WHITE);
typedArray.recycle();
stripePaint = new Paint();
stripePaint.setColor(itemColor);
stripePaint.setAntiAlias(true);
stripePaint.setStyle(Paint.Style.FILL);
stripeSelectedPaint = new Paint();
stripeSelectedPaint.setColor(itemSelectColor);
stripeSelectedPaint.setAntiAlias(true);
stripeSelectedPaint.setStyle(Paint.Style.FILL);
titleTextPaint = new Paint();
titleTextPaint.setColor(titleTextColor);
titleTextPaint.setTextSize(titleTextSize);
titleTextPaint.setAntiAlias(true);
bodyBackGroundPaint = new Paint();
bodyBackGroundPaint.setColor(bodyBackGroundColor);
bodyBackGroundPaint.setStyle(Paint.Style.FILL);
titleBackGroundPaint = new Paint();
titleBackGroundPaint.setColor(titleBackGroundColor);
titleBackGroundPaint.setStyle(Paint.Style.FILL);
touchEventCountThread = new TouchEventCountThread();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
centerX = (width - itemWidth) / 2;
if (values != null && values.size() > 0) {
startX = ((width / 2) + (itemWidth / 2)) - ((itemWidth * values.size()) + ((values.size() - 1) * itemSpaceWidth));
}
titleHeight = titleTextSize + (titleTextLineSpace * 2);
itemHeight = (height - titleHeight) / maxValue;
titleTextY = height - titleTextSize;
// 主背景
canvas.drawRect(0f, 0, width, height - titleHeight, bodyBackGroundPaint);
// 标题背景
canvas.drawRect(0f, height - titleHeight, width, height, titleBackGroundPaint);
if (values != null && values.size() > 0 && titles != null && titles.size() == values.size()) {
for (int i = 0; i < values.size(); i++) {
int value = values.get(i);
float left = startX + (itemWidth + itemSpaceWidth) * i + moveWidth;
float top = height - titleHeight - (itemHeight * value);
float right = left + itemWidth;
float bottom = height - titleHeight;
String title = titles.get(i);
float textWidth = titleTextPaint.measureText(title, 0, title.length());
float textX = left + ((itemWidth - textWidth) / 2);
// 判断是否中心
if (left >= centerX && left <= (width + itemWidth) / 2) {
canvas.drawRect(left, top, right, bottom, stripeSelectedPaint);
// 标题
titleTextPaint.setColor(titleTextSelectColor);
canvas.drawText(title, textX, titleTextY, titleTextPaint);
if (i == 0 || selectPosition != i) {
Message message = handler.obtainMessage();
message.what = HANDLER_WHAT_SELECT_CHANGE;
message.arg1 = i;
message.sendToTarget();
}
selectPosition = i;
} else {
canvas.drawRect(left, top, right, bottom, stripePaint);
// 标题
titleTextPaint.setColor(titleTextColor);
canvas.drawText(title, textX, titleTextY, titleTextPaint);
}
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchStarX = event.getX();
isMove = false;
isUp = false;
postDelayed(touchEventCountThread, 100);
if(parentViewGroup != null){
parentViewGroup.requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_MOVE:
isMove = true;
if (Math.abs(event.getX() - touchStarX) > 1) {
moveWidth += event.getX() - touchStarX;
postInvalidate();
touchStarX = event.getX();
}
break;
case MotionEvent.ACTION_UP:
isUp = true;
if (isMove) {
aligning();
}
if(parentViewGroup != null){
parentViewGroup.requestDisallowInterceptTouchEvent(false);
}
break;
}
//return super.onTouchEvent(event);
return true;
}
/**
* 对齐,让靠中间的条形移至正中间
*/
private void aligning() {
if(values == null || values.isEmpty()){
return;
}
Float tagX = null;
Float tagXValue = null;
for (int i = 0; i < values.size(); i++) {
float left = startX + (itemWidth + itemSpaceWidth) * i + moveWidth;
float distance = Math.abs(centerX - left);
if (tagX == null || distance < tagX) {
tagX = distance;
tagXValue = centerX - left;
}
}
if (tagX != null) {
moveWidth += tagXValue;
}
isMove = false;
postInvalidate();
}
public void setValue(List<Integer> values) {
this.values = values;
selectPosition = 0;
}
public void setTitle(List<String> titles) {
this.titles = titles;
}
public void refresh() {
postInvalidate();
}
private int dip2px(float dpValue) {
final float scale = getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
private float sp2px(float spValue) {
final float scale = getContext().getResources().getDisplayMetrics().scaledDensity;
return (spValue * scale + 0.5f);
}
class TouchEventCountThread implements Runnable {
@Override
public void run() {
if (!isMove && isUp && values != null && values.size() > 0 && titles != null && titles.size() == values.size()) {
for (int i = 0; i < values.size(); i++) {
float left = startX + (itemWidth + itemSpaceWidth) * i + moveWidth;
float right = left + itemWidth;
if (touchStarX >= left && right >= touchStarX) {
selectTo(i);
if (onStripeStaticsListener != null) {
Message message = handler.obtainMessage();
message.what = HANDLER_WHAT_CLICK;
message.arg1 = i;
message.sendToTarget();
}
break;
}
}
}
}
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case HANDLER_WHAT_CLICK:
if(onStripeStaticsListener != null) {
onStripeStaticsListener.onItemClick(msg.arg1);
}
break;
case HANDLER_WHAT_SELECT_CHANGE:
if(onStripeStaticsListener != null) {
onStripeStaticsListener.onSelectChanged(msg.arg1);
}
break;
}
}
};
public void selectTo(int position) {
if (selectPosition == position) {
return;
}
if (position > selectPosition) {
moveWidth -= ((itemWidth + itemSpaceWidth) * (position - selectPosition));
} else {
moveWidth += ((itemWidth + itemSpaceWidth) * (selectPosition - position));
}
postInvalidate();
}
public interface OnStripeStaticsListener {
void onItemClick(int position);
void onSelectChanged(int position);
}
public void setOnStripeStaticsListener(OnStripeStaticsListener onClickListener) {
this.onStripeStaticsListener = onClickListener;
}
public void setParentViewGroup(ViewGroup parentViewGroup) {
this.parentViewGroup = parentViewGroup;
}
}
attr.xml添加属性
<declare-styleable name="StripeStaticsView">
<attr name="itemWidth" format="dimension" />
<attr name="itemColor" format="color" />
<attr name="itemSelectColor" format="color" />
<attr name="itemSpaceWidth" format="dimension" />
<attr name="maxValue" format="integer" />
<attr name="titleTextSize" format="dimension" />
<attr name="titleTextLineSpace" format="dimension" />
<attr name="titleTextColor" format="color" />
<attr name="titleTextSelectColor" format="color" />
<attr name="contentBGColor" format="color" />
<attr name="titleBGColor" format="color" />
</declare-styleable>
使用
<xxx.StripeStaticsView
android:id="@+id/stripeStaticsView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/statics_stripe_view_margin_top"
app:contentBGColor="#7dded4"
app:itemColor="#80ffffff"
app:itemSelectColor="@android:color/white"
app:itemSpaceWidth="5dp"
app:itemWidth="30dp"
app:maxValue="100"
app:titleBGColor="@android:color/white"
app:titleTextColor="@color/txt_describe"
app:titleTextLineSpace="8dp"
app:titleTextSelectColor="@color/colorPrimary"
app:titleTextSize="10sp" />
// 设置值
void setValue(List<Integer> values)
// 设置值对应的标题(注:数量要对应)
void setTitle(List<String> titles)
// 设置标题和内容后刷新控件
void refresh()
// 控件添加在上下滑动控件中时,当手在该控件左右滑动时不会触发上下滑动,添强体验,如ListView
void setParentViewGroup(ViewGroup parentViewGroup)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。