Android表格自定义控件使用详解

近期公司要做报表功能,在网上搜索下表格的样式后便自己写了一个自定义的表格控件,该表格控件能根据设置的数据中数据的最大值自动设置左侧信息栏显示的值,使得条形图能尽量的充满控件,条形图部分支持左右滑动,数据的长度可能超过控件本身所能容纳的长度,所以在绘制的时候做了判断,当需要绘制的部分不再控件范围内则不进行绘制,具体请阅读代码,目前只支持一个名称对应一条数据,如有不足之处,大家提出帮忙修改
使用方法如下:
在xml文件中定义控件属性


在Activity中设置控件要显示的数据、设置显示的样式
public class MainActivity extends AppCompatActivity {private MyChatView mMyChatView; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMyChatView = (MyChatView) this.findViewById(R.id.chatView); mMyChatView.setData(getData1()).setDataCompany("美元").setDataTitle("测试").setLeftTextColor(Color.RED).setBottomTextColor(Color.BLUE).setmDataTopTextColor(Color.RED).setDataBackgroundColor(Color.parseColor("#ABCDEF")).setDataColor(Color.RED).setTitleColor(Color.BLUE).setLeftTextSize(12).setBottomTextSize(15).setDataTopTextSize(10).setTitleTextSize(20).setSpanBottomText(15); }/*** 获取测试数据* @return 测试用的数据*/private List getData1(){List data = https://www.it610.com/article/new ArrayList<>(); HashMap map; int temp; for (int i=0; i<100; i++) {map = new HashMap<>(); map.put(MyChatView.NAME, "name:"+i); temp = (int) (Math.random()*100); map.put(MyChatView.VALUE, temp +"."+i*i); data.add(map); }return data; }}

自定义控件代码:
public class MyChatView extends View {/** 数据集合中的 Map 集合存放信息的键 */public static final String NAME = "name"; /** 数据集合中的 Map 集合存放数据的键 */public static final String VALUE = "https://www.it610.com/article/value"; /** 上下文 */private Context mContext; /** 控件的高度 */private int mHeight; /** 控件的宽度 */private int mWidget; /** 数据 */private List mData; /** 数据单位 */private String mDataCompany = "单位: "; /** 底部表格名称 */private String mDataTitle = null; /** 底部信息栏文字的大小 */private int mBottomTextSize; /** 左侧等分信息栏文字的大小 */private int mLeftTextSize; /** 柱状图顶部文字的大小 */private int mDataTopTextSize; /** 表格标题文字大小 */private int mTitleTextSize; /** 左侧文字与数据区域的间隔 */private int mSpanLeftText; /** 柱状图顶部文字与柱状图的间隔 */int mSpanDataTopText; /** 底部信息字符串间隔 */int mSpanBottomText; /** 底部信息字符串与控件底部间隔 */int mSpanBottom; /** 绘制数据部分的背景颜色 */private int mDataBackgroundColor = Color.WHITE; /** 底部信息字符串颜色 */private int mBottomTextColor = Color.BLACK; /** 柱状图柱状部分颜色 */private int mDataColor = Color.BLACK; /** 左边信息栏文字颜色 */private int mLeftTextColor = Color.BLACK; /** 柱状图顶部文字颜色 */private int mDataTopTextColor = Color.BLACK; /** 标题颜色 */private int mTitleColor = Color.BLACK; /** 表格移动的位置 */private int mChartMovedSize = 0; /** 用户按下时 X 方向位置 */private int mDownX = 0; /** 用户松手是 X 方向位置 */private int mUpX = 0; /** 表格 X 方向移动的最大距离 */private int mChartMaxMovedLengthX; public MyChatView(Context context) {this(context, null); }public MyChatView(Context context, AttributeSet attrs) {this(context, attrs, 0); }public MyChatView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr); this.mContext = context; this.mBottomTextSize = dpToPx(context, 15); this.mLeftTextSize = dpToPx(context, 10); this.mDataTopTextSize = dpToPx(context, 10); this.mSpanLeftText = dpToPx(context, 2); this.mSpanDataTopText = dpToPx(context, 3); this.mSpanBottomText = dpToPx(context, 10); this.mSpanBottom = dpToPx(context, 8); this.mTitleTextSize = dpToPx(context, 20); }@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh); this.mHeight = h; this.mWidget = w; }@Overridepublic boolean onTouchEvent(@NonNull MotionEvent event) {int action = event.getAction(); switch (action) {case MotionEvent.ACTION_DOWN:mDownX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE:mUpX = (int) event.getX(); shouldMoveChart(); break; case MotionEvent.ACTION_UP:mUpX = (int) event.getX(); shouldMoveChart(); break; }return true; }/*** 判断移动的距离大于规定距离就移动表格*/private void shouldMoveChart (){if (mChartMaxMovedLengthX=size || (mDownX-mUpX)>=size ) {mChartMovedSize += (mUpX - mDownX); mDownX = mUpX; if (mChartMovedSize>=0) {mChartMovedSize = 0; }if (mChartMovedSize<-mChartMaxMovedLengthX) {mChartMovedSize = -mChartMaxMovedLengthX; }this.invalidate(); }}private InnerDraw innerDraw; @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas); if (innerDraw==null) {innerDraw = new InnerDraw(canvas); } else {innerDraw.initData(canvas); }innerDraw.drawLeftMenue(); innerDraw.drawDataBackground(); innerDraw.drawDataTitle(); innerDraw.drawCompany(); int dataSize = mData.size(); for (int i=0; i10) {maxValue = https://www.it610.com/article/maxValue/10; piceValue = piceValue * 10; }if (maxValue<=5) {piceValue = piceValue / 2; }return piceValue; }/*** 根据手机的分辨率从 dp 的单位 转成为 px(像素)* @param context 上下文* @param dpValue 要转换的 dp 值* @return 转换后的 px 值*/private int dpToPx(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); }/*** 设置数据* @param data 表中的数据*data集合中的Map*"name"存放名称,使用MyCharView中的常量 NAME*"value"存放数据,数据为int类型的字符串,使用MyCharView中的常量 VALUE*/public MyChatView setData (List data){try {this.mData = https://www.it610.com/article/data==null? new ArrayList():data; }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置绘制数据部分背景颜色* @param dataBackgroundColor 16进制 int 类型颜色* @return 对象本身*/public MyChatView setDataBackgroundColor (int dataBackgroundColor){try {this.mDataBackgroundColor = dataBackgroundColor; }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置左边信息栏文字颜色* @param leftTextColor 16进制 int 类型颜色* @return 对象本身*/public MyChatView setLeftTextColor (int leftTextColor){try {this.mLeftTextColor = leftTextColor; }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置底部信息文字颜色* @param bottomTextColor 16进制 int 类型颜色* @return 对象本身*/public MyChatView setBottomTextColor (int bottomTextColor){try {this.mBottomTextColor = bottomTextColor; }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置柱状条的背景颜色* @param dataColor 16进制 int 类型颜色* @return 对象本身*/public MyChatView setDataColor (int dataColor){try {this.mDataColor = dataColor; }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置柱状条顶部文字颜色* @param dataTopTextColor 16进制 int 类型颜色* @return 对象本身*/public MyChatView setmDataTopTextColor (int dataTopTextColor){try {this.mDataTopTextColor = dataTopTextColor; }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置标题颜色* @param titleColor 颜色16进制的 int 类型* @return 对象本身*/public MyChatView setTitleColor (int titleColor){try {this.mTitleColor = titleColor; }catch (Exception e){e.printStackTrace(); }return this; }/*** 设置底部信息文字大小* @param bottomTextSize int 类型 dp* @return 对象本身*/public MyChatView setBottomTextSize (int bottomTextSize){try {this.mBottomTextSize = dpToPx(mContext, bottomTextSize); }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置左侧信息文字大小* @param leftTextSize int 类型 dp* @return 对象本身*/public MyChatView setLeftTextSize (int leftTextSize){try {this.mLeftTextSize = dpToPx(mContext, leftTextSize); }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置柱状条顶部文字大小* @param dataTopTextSize int 类型 dp* @return 对象本身*/public MyChatView setDataTopTextSize (int dataTopTextSize){try {this.mDataTopTextSize = dpToPx(mContext, dataTopTextSize); }catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置底部表格标题文字大小* @param titleTextSize 标题文字大小* @return 对象本身*/public MyChatView setTitleTextSize (int titleTextSize){try {this.mTitleTextSize = dpToPx(mContext,titleTextSize); } catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置表格数据单位* @param dataCompany 数据单位* @return 对象本身*/public MyChatView setDataCompany (String dataCompany){try {this.mDataCompany += dataCompany==null? "空":dataCompany; } catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置表格标题* @param dataTitle 表格标题* @return 对象本身*/public MyChatView setDataTitle (String dataTitle){try {mDataTitle = dataTitle; } catch (Exception e) {e.printStackTrace(); }return this; }/*** 设置底部信息栏文字的间隔 默认为 10dp* @param spanBottomText 间隔距离 dp* @return 对象本身*/public MyChatView setSpanBottomText (int spanBottomText){try {this.mSpanBottomText = dpToPx(mContext, spanBottomText); } catch (Exception e){e.printStackTrace(); }return this; }//****************************** 绘制表格的类 **********************************/*** 绘制控件界面的类*/private class InnerDraw{private Canvas canvas; privatePaint paint; /** 记录绘制到的位置 */privateint bottomTextPainted; /** 底部标题高度 */privateint bottomTitleHeight; /** 底部信息的高度 */privateint bottomMessageHeight; /** 左侧信息栏最长文字 */privateString leftValueMaxString; /** 表格中柱状图上文字高度 */privateint dataTopTextHeight; /** 左侧信息栏宽度 */privateint leftValueWidth; /** 绘制数据部分的高度 */privateint chartDataHeight; /** 左侧等分栏的每等分高度 */privateint piceValueHeight; /** 左侧等分栏每等分的数值 */privateint piceValue; /** 柱状的宽度 */privateint dataBarWidth; /** 底部信息 */String bottomMessage; /** 底部信息的宽度 */private int bottomMessageWidth; /** 数据信息 */Map data; /** 要绘制信息的位置 */int index; public InnerDraw (Canvas canvas){initData(canvas); }/*** 初始化数据*/public void initData(Canvas canvas){this.canvas = canvas; this.paint = new Paint(); this.bottomTitleHeight = mDataTitle==null? 0:(getTextHeight(paint, mTitleTextSize)+mSpanBottom/2); this.bottomTextPainted = 0; this.bottomMessageHeight = getTextHeight(paint, mBottomTextSize) +mSpanBottom + bottomTitleHeight; this.leftValueMaxString = getLeftValueMaxString(); this.dataTopTextHeight = getTextHeight(paint, mDataTopTextSize); this.leftValueWidth = getTextWidth(paint, leftValueMaxString , mLeftTextSize) + mSpanLeftText; this.chartDataHeight = mHeight - bottomMessageHeight - mSpanBottom; this.piceValueHeight = (chartDataHeight-dataTopTextHeight-getTextHeight(paint, mSpanDataTopText))/10; this.piceValue = https://www.it610.com/article/getPiceValue(getMaxValue()); this.dataBarWidth = getTextWidth(paint, getBottomMaxLegthString(), mBottomTextSize); this.bottomMessage =""; this.bottomMessageWidth = 0; this.data = https://www.it610.com/article/new HashMap<>(); this.index = 0; }/*** 绘制左侧等分栏*/public void drawLeftMenue(){paint.setColor(mLeftTextColor); paint.setTextSize(mLeftTextSize); int textLeft; int textTop; String valueStr; int strLength; String maxValueStr = String.valueOf(piceValue * 10); int textMaxLength = maxValueStr.length(); int topTextHeight = getTextHeight(paint, mDataTopTextSize); int leftTextHeight = getTextHeight(paint, mLeftTextSize); for (int i=0; i<=10; i++) {textLeft = 0; valueStr = String.valueOf(i * piceValue); strLength = valueStr.length(); if (strLengthmWidget) {//需要绘制的区域超出了控件的右边,结束绘制return -1; }return 1; }/*** 结束绘制*/public void endDrawBody(){bottomTextPainted += bottomMessageWidth; }/*** 绘制底部信息栏*/public void drawBottomMessage() {paint.setColor(mBottomTextColor); paint.setTextSize(mBottomTextSize); int bottomLeft = (index + 1) * mSpanBottomText + mChartMovedSize + leftValueWidth + bottomTextPainted; int bottomTop = chartDataHeight + bottomMessageHeight - bottomTitleHeight - dpToPx(mContext, 2); if (bottomLeft >= leftValueWidth && bottomLeft < mWidget) {canvas.drawText(bottomMessage, bottomLeft, bottomTop, paint); } else if ((bottomLeft+bottomMessageWidth)>leftValueWidth) {int index = (leftValueWidth-bottomLeft)*bottomMessage.length()/bottomMessageWidth+1; if (index>=0 && index leftValueWidth) {dataLeft = leftValueWidth; }Rect dataRect = new Rect(dataLeft, dataTop, dataRight, dataBottom); if (dataRight>leftValueWidth) {canvas.drawRect(dataRect, paint); }}/*** 绘制条形数据顶部文字*/public void drawDataTopText() {String topTextMessage = data.get(VALUE); int topTextWidth = getTextWidth(paint, topTextMessage, mDataTopTextSize); paint.setColor(mDataTopTextColor); paint.setTextSize(mDataTopTextSize); int bottomLeft = (index + 1) * mSpanBottomText + mChartMovedSize + leftValueWidth + bottomTextPainted; int topTextLeft = bottomLeft + (bottomMessageWidth - topTextWidth) / 2; int dataValue = https://www.it610.com/article/Float.valueOf(data.get(VALUE)).intValue(); int dataTop = chartDataHeight - (dataValue*(chartDataHeight-dataTopTextHeight - mSpanDataTopText)/piceValue)/10; int topTextTop = dataTop - mSpanDataTopText * 2 / 3; if (topTextLeft>= leftValueWidth && bottomLeft < mWidget) {canvas.drawText(topTextMessage, topTextLeft, topTextTop, paint); } else if ((topTextLeft+topTextWidth)>leftValueWidth) {int index = (leftValueWidth-topTextLeft)*topTextMessage.length()/topTextWidth+1; if (index>=0 && index
实现效果如下图
Android表格自定义控件使用详解
文章图片

【Android表格自定义控件使用详解】以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

    推荐阅读