本文出自:http://blog.csdn.net/dt235201314/article/details/78085430
一丶效果展示
二丶需求分析及技术点
- 1.显示每个季度产业(收入)占比,低于5%不显示
与上篇类似,将View换成textView即可,高度小于5%不显示
- 2.产业颜色与下面显示显色一致,且严格按照设计图颜色
使用map,键值对,一个产业名对应一个颜色
- 3.柱状图可滑动
同上篇博客
http://blog.csdn.net/dt235201314/article/details/77534468
- 4.带有动画效果
用白色View遮盖,由下往上收起,形成动画效果
- 5.图解
三丶看代码
xml
item_text_bar.xml
与上篇背景布局类似,HorizontalScrollView控制左右滑动,动态添加柱状图,以及FlowLayout(自适应布局显示下标)
说一说FlowLayout
bulid添加依赖便可以使用
compile 'com.nex3z:flow-layout:0.1.4'
属性讲解参看其他文章:
之前写的文章:
Android删除添加标签(FlowLayout案例)
自定义ViewGroup
TextBarGroupView.java
public class TextBarGroupView extends LinearLayout {
public TextBarGroupView(Context context) {
super(context);
setOrientation(HORIZONTAL);
}
public TextBarGroupView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
}
public TextBarGroupView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOrientation(HORIZONTAL);
}
String other = "其它";
public void init(final List datas, final int barHeight, FlowLayout sourceContainer) {
removeAllViews();
if (datas == null || datas.isEmpty()) {
return;
}
List colors = new ArrayList<>();
colors.add(Color.parseColor("#3fa0ff"));
colors.add(Color.parseColor("#98b3e5"));
colors.add(Color.parseColor("#d7546d"));
colors.add(Color.parseColor("#51d4c4"));
colors.add(Color.parseColor("#6d43cc"));
colors.add(Color.parseColor("#ffb256"));
colors.add(Color.parseColor("#69390e"));
colors.add(Color.parseColor("#7ab024"));
colors.add(Color.parseColor("#a7d0c8"));
colors.add(Color.parseColor("#a29258"));
colors.add(Color.parseColor("#297350"));
colors.add(Color.parseColor("#eebdc7"));
colors.add(Color.parseColor("#bb59d0"));
List allSourceList = new ArrayList<>();
List allSourceNameList = new ArrayList<>();
Map nameColorMap = new HashMap<>();
final int lineHeight = (int) getResources().getDisplayMetrics().density * 1;
for (int i = 0; i < datas.size(); i++) {
//加载所有来源,去重复
List sourceList = datas.get(i).getSourceList();
if (sourceList != null && !sourceList.isEmpty()) {
int j = 0;
for (TextBarDataEntity.Record.Source entry : sourceList) {
if (!nameColorMap.containsKey(entry.getSourceName())) {
Integer colorValue = colors.get(j % colors.size());
if (!nameColorMap.containsValue(colorValue)) {
nameColorMap.put(entry.getSourceName(), colorValue);
} else {
int index=colors.indexOf(colorValue);
for(int x=index;x list, FlowLayout sourceContainer, Map nameColorMap) {
sourceContainer.removeAllViews();
for (TextBarDataEntity.Record.Source source : list) {
View item = LayoutInflater.from(getContext()).inflate(R.layout.pie_lable_item, sourceContainer, false);
GradientDrawable bg = (GradientDrawable) item.findViewById(R.id.icon).getBackground();
TextView txt = (TextView) item.findViewById(R.id.txt);
bg.setColor(nameColorMap.get(source.getSourceName()));
item.findViewById(R.id.icon).setBackground(bg);
txt.setText(source.getSourceName());
sourceContainer.addView(item);
}
}
}
- init()方法
第一个参数 Listdatas 为实体类展示数据
造数据核心代码:
public List parseData(){
recordList = new ArrayList<>();
Random r = new Random();
for (int i= 0;i<=4;i++){
Record record = new Record();
record.setTimeScale("第" + (i+1) + "周");
List list = new ArrayList<>();
for (int j=0; j<= 3; j++ ){
Record.Source source = new Record.Source();
source.setSourceName("TCL第" + (j+1) + "产业");
source.setSourceNum(r.nextInt(10*(j+1)));
list.add(source);
}
Record.Source source = new Record.Source();
source.setSourceName("TCL第5产业");
int sourceNum = 100 - list.get(0).getSourceNum() - list.get(1).getSourceNum()
- list.get(2).getSourceNum() - list.get(3).getSourceNum();
source.setSourceNum(sourceNum);
list.add(source);
record.setSourceList(list);
recordList.add(record);
}
return recordList;
}
随机数10,20,30,40以内,最后100前去前面的数,刚好100,除以100为占比数
第二个参数 int barHeight 高度
这里为柱状图高度,5倍上面的那个横线布局 id item0 高度
第三个参数 FlowLayout sourceContainer定义view容器
动态添加子view,“第1产业”
看for循环(是不是很牛逼的感觉)
运用map,一个产业名对应一个颜色数值
注意了,为什么后面要循环遍历,因为各个季度产业数可能不同,例:季度一(1 2 3 4产业)季度二(3 4 5 6产业)
Collections.reverse(sourceList);
这一句,逆序展示业务要求(后台排好大小顺序)
- initAllSourceLayout()方法
第一个参数 Listlist 产业名称
第二个参数 FlowLayout sourceContainer 容器
pie_lable_item.xml
第三个参数 Map
看代码,这个方法就是添加效果图下面的,产业1 2 3...了
第二个for循环(添加自定义View带文字柱状图 + 动画实现)
text_source_item_group.xml(这个带文字柱状的布局)
这里FrameLayout,用一个白色View遮住TextBarView收起形成动画
TextBarView.java
public class TextBarView extends LinearLayout {
public TextBarView(Context context) {
super(context);
setOrientation(VERTICAL);
}
public TextBarView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(VERTICAL);
}
public TextBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOrientation(VERTICAL);
}
DecimalFormat format = new DecimalFormat("##.##");
PopupWindow popupWindow;
View popView;
public void init(TextBarDataEntity.Record record, int height, Map nameColorMap) {
if (record.getSourceList() == null && record.getSourceList().isEmpty()) {
return;
}
popView = LayoutInflater.from(getContext()).inflate(
R.layout.pop_bg, null);
//计算空白填充部分占比
double blankScale = 1;
for (int i = 0; i < record.getSourceList().size(); i++) {
blankScale -= record.getSourceList().get(i).getSourceNum();
}
// if (blankScale==1) {
// TextView item = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.negative_sentiment_source_item_txt, this, false);
// ViewGroup.LayoutParams lp = item.getLayoutParams();
// lp.height = (int) (blankScale * height);
// addView(item);
// return;
// }
for (int i = 0; i < record.getSourceList().size(); i++) {
final TextView item = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.text_source_item_txt, this, false);
final TextBarDataEntity.Record.Source source = record.getSourceList().get(i);
item.setText(source.getSourceNum() >= 5 ? format.format(source.getSourceNum()) + "%" : "");
GradientDrawable bg = (GradientDrawable) getResources().getDrawable(R.drawable.n_s_bar_bg);
bg.setColor(nameColorMap.get(source.getSourceName()));
item.setBackground(bg);
ViewGroup.LayoutParams lp = item.getLayoutParams();
lp.height = (int) (source.getSourceNum()/(double)100 * height);
addView(item, lp);
}
}
private void showPop(final View view) {
if (popupWindow != null)
popupWindow.dismiss();
popupWindow = null;
popupWindow = new PopupWindow(popView,
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false);
popupWindow.setBackgroundDrawable(new BitmapDrawable());
popupWindow.setOutsideTouchable(true);
popupWindow.showAsDropDown(view, view.getWidth() / 2, view.getHeight() / 2);
}
}
这里与上一篇的BarView类似,带文字柱状图就没必要再点击弹框了
直接看init()方法的for循环
text_source_item_txt.xml (就是一个textview)
item.setText(source.getSourceNum() >= 5 ? format.format(source.getSourceNum()) + "%" : "");
小于5%,不显示
添加bg
lp.height = (int) (source.getSourceNum()/(double)100 * height);
这里表示每个text站总高度的百分比,必须加上double
白色view揭盖动画
获取高度运用ObjectAnimator收起
给自定义带文字布局添加topMargin
getViewTreeObserver().
动态测量高度
四丶往期文章
MPAndroidChart常见设置属性(一)——应用层
MPAndroidChart项目实战(一)——实现对比性柱状图
MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现
MPAndroidChart项目实战(三)——饼状图实现和文字重合问题解决
MPAndroidChart项目实战(四)——柱状图实现及X轴文字不显示问题和柱状图上显示文字
MPAndroidChart X轴文字斜着显示
MPAndroidChart项目实战(五)——组合图实现趋势图
MPAndroidChart项目实战(六)——自定义1MPAndroidChart滑动冲突解决(搞不定产品设计师就只能搞自己)
MPAndroidChart项目实战(七)——自定义横向柱状图
MPAndroidChart项目实战(八)——自定义分段堆积柱状图
MPAndroidChart项目实战(九)——自定义带文字分段堆积柱状图