安卓横向柱状图,逻辑与实现
网上有很多图标的开源工程。实现图表类型也是丰富多样,如:线图、柱形图、饼图、散点图、仪表图、雷达图、热力图、混合图等。
点击跳转到第二版
https://blog.csdn.net/yu1441/article/details/81129430
然而一般的柱状图却并不适合在手机上面展示数据。毕竟手机屏幕就那么大,而且大部分功能性APP都是竖着用。列一旦多了,后面就显示不下,如果把行距缩小,那么底部文字又显示不下。为了适应手机屏幕,横向柱状图才是最实用,解决了很多不能完全显示问题。但是好几个主流的chart并没有横向柱状图。为什么没有?估计是因为太简单了,别人都不想做成控件。
首先来看看demo效果
图片1 | 图片1 |
---|---|
GIF动画:
首先在activity的xml放入:
<LinearLayout
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:orientation="vertical">
</LinearLayout>
然后是柱状图部分xml代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="8dp"
android:paddingRight="8dp"
>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingRight="10dp">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:singleLine="true"
android:ellipsize="end"
android:text="name" />
</LinearLayout>
<LinearLayout
android:id="@+id/bar_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3.2"
android:gravity="left|center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/bar"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:background="#0CD3F4" />
<TextView
android:id="@+id/percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:text="0%"
android:textColor="#0CD3F4" />
</LinearLayout>
</LinearLayout>
activity中关键代码:
private void showColumnar() {
linearlayout.removeAllViews();
//赋值
for (int i = 0; i < 30; i++) {
//随机产生一个进度
final double ranNum = Math.random() * 100;
//设置最大值
final double finalMaxScale = 100;
final View item = LayoutInflater.from(this).inflate(R.layout.columnar_item, linearlayout, false);
final TextView name = item.findViewById(R.id.name);
final TextView percent = item.findViewById(R.id.percent);
final View bar = item.findViewById(R.id.bar);
final LinearLayout container = item.findViewById(R.id.bar_container);
name.setText("测试数据" + i);
bar.setBackgroundColor(Color.parseColor("#3FA0FF"));
percent.setText(format.format(ranNum) + "%");
percent.setTextColor(Color.parseColor("#3FA0FF"));
item.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
item.getViewTreeObserver().removeOnPreDrawListener(this);
//计算出进度条可用宽度(进度条到最后屏幕的宽度-后面显示%的宽度)
final int initWidth = container.getWidth() - percent.getWidth();
//计算出进度条应该显示的宽度
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) bar.getLayoutParams();
lp.width = (int) (initWidth * ranNum / finalMaxScale);
bar.setLayoutParams(lp);
//定时器
item.postDelayed(new Runnable() {
@Override
public void run() {
//获取bar应该显示宽度
final int initWidth = bar.getWidth();
//设置动画,1.5秒内从0.0宽度变成1.0宽度(1.0代表100%)
final ObjectAnimator anim = ObjectAnimator.ofFloat(bar, "alpha", 0.0F, 1.0F).setDuration(1500);
//动画监听
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//事实计算宽度,应该显示的宽度乘以当前进度,再事实设置给bar
float cVal = (Float) anim.getAnimatedValue();
lp.width = (int) (initWidth * cVal);
bar.setLayoutParams(lp);
}
});
//动画开始
anim.start();
}
}, 0);
return false;
}
});
//设置隔断并添加隔断到linearlayout
TextView textView = new TextView(this);
textView.setHeight(dip2px(10));
linearlayout.addView(textView);
//添加item到添加隔断到linearlayout
linearlayout.addView(item);
}
}