android自定义柱状图表,Android自定义柱状图控件

搜索github会发现已经有很多相对成熟的图表框架,但与我们拿到的ui效果图总会有一些差别,然后就会陷入是把别人源码下载下来修改之后作为已用,或是重新定义一个新控件的两难境地。初拿到效果图感觉还是比较复杂难以实现,但是仔细观察发现其实这就是一个列表,一个横向列表,一个可以用RecyclerView实现的列表。

a6d648e99248

效果图.gif

如果借助recyclerview的话,那么重点就在每个条目也就是柱状图每个柱子的实现。

public class BarGraphItem extends View {

private static final String TAG = "BarGraphView";

private Paint paint;

private int measuredWidth;

private int measuredHeight;

private double ratio;

private GradientDrawable gradientDrawable;

public BarGraphItem(Context context) {

super(context);

initPaint();

}

public BarGraphItem(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

initPaint();

}

public BarGraphItem(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

initPaint();

}

//设置柱子的高度

public void setRatio(double ratio) {

this.ratio = ratio;

invalidate();

}

private void initPaint() {

paint = new Paint();

paint.setStyle(Paint.Style.FILL);

paint.setColor(getResources().getColor(R.color.colorBarBack));

paint.setAntiAlias(true);

int colors[] = {getResources().getColor(R.color.colorBarColor), getResources().getColor(R.color.colorGradientGreen)};

gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP,colors);

//设置渐变色

gradientDrawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);

//设置顶部圆角

gradientDrawable.setCornerRadii(new float[]{15,15,15,15,0,0,0,0});

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

measuredWidth = getMeasuredWidth();

measuredHeight = getMeasuredHeight();

}

@Override

protected void onDraw(Canvas canvas) {

//画柱子的背景色

canvas.drawRect(0, 0, measuredWidth, measuredHeight, paint);

//计算柱子实际高度

if (ratio != 0){

int ratioHeight = (int) (measuredHeight * ratio + 0.5);

//默认坐标原点在左上角,这里我们把画布移到左上角

canvas.translate(0,measuredHeight - ratioHeight);

//x,y,w,h

gradientDrawable.setBounds(0,0,measuredWidth, ratioHeight);

gradientDrawable.draw(canvas);

}

}

}

代码并不复杂,可以看到最终效果有很多渐变色的运用,平时我们会用shape标签绘制一些简单的图形,其中有一个gradient属性可以帮我们实现渐变效果,那在代码中可以直接使用GradientDrawable来实现同样的效果。接下来在布局文件中使用

android:orientation="vertical"

xmlns:android="http://schemas.android.com/apk/res/android"

android:gravity="center_horizontal"

android:paddingTop="4dp"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

android:textSize="9dp"

android:text="--"

android:id="@+id/tv_amount_bar_graph"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

android:id="@+id/rl_bar_graph"

android:layout_marginTop="8dp"

android:background="@drawable/shape_bar_graph"

android:layout_width="43dp"

android:layout_height="wrap_content">

android:layout_centerHorizontal="true"

android:id="@+id/bgi_bar_graph"

android:layout_gravity="center_horizontal"

android:layout_width="8dp"

android:layout_height="110dp" />

android:textColor="#999999"

android:textSize="12dp"

android:gravity="center"

android:text="--"

android:background="#F9F9F9"

android:layout_marginTop="8dp"

android:id="@+id/tv_time_bar_graph"

android:layout_width="match_parent"

android:layout_height="40dp" />

android:id="@+id/iv_highest_bar_graph"

android:visibility="invisible"

android:src="@drawable/triangle_red_rose"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

因为柱状图整体的渐变背景并没到底部,只是中间柱子的部分,所以把这个背景的设置放到item的布局中,也是用shape 标签实现

android:shape="rectangle">

android:angle="90"

android:startColor="@color/colorLightBlue"

android:endColor="@color/colorGradientWhite"

>

标识最高点的红色三角可以用png或其它格式的图片,为了尽量缩减包体积也可以用layerlist标签来实现,

android:fromDegrees="45"

android:toDegrees="45"

android:pivotX="-40%"

android:pivotY="80%">

android:height="8dp"/>

准备工作已经完成,接下来就可以愉快地进行recyclerview三步曲了。在xml布局文件中使用recyclerview(比较简单代码就省略了),然后在MainActivity中初始化recyclerview,

private void initRecyclerView() {

//先造几条假数据

DecimalFormat df = new DecimalFormat("0.00");

int maxIndex = 0;

double max = 0;

for (int i = 1;i <= 10;i++){

IncomeDetailsBean incomeDetailsBean = new IncomeDetailsBean();

incomeDetailsBean.setDate(i + "点");

double random = Math.random();

//记录最大值

if (random > max) {

max = random;

maxIndex = i - 1;

}

incomeDetailsBean.setIncome(df.format(random * 10) + "");

incomeDetailsBean.setRatio(random);

incomeDetails.add(incomeDetailsBean);

}

incomeDetails.get(maxIndex).setHighest(true);

//初始化recyclerview

layoutManager = new LinearLayoutManager(this);

layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

recyclerView.setLayoutManager(layoutManager);

barGraphAdapter = new BarGraphAdapter(this,incomeDetails);

recyclerView.setAdapter(barGraphAdapter);

}

最后一步adapter,只看绑定控件这一部分,

@Override

public void onBindViewHolder(ViewHolder holder, int position) {

//如果没有数据会有几条占位图

if (incomeDetails == null || incomeDetails.size() == 0){

holder.barGraphItem.setRatio(0);

holder.tv_time.setText("--");

holder.tv_amount.setText("--");

if (View.VISIBLE == holder.iv_highest.getVisibility()) {

holder.iv_highest.setVisibility(View.INVISIBLE);

holder.tv_time.setTextSize(12);

holder.tv_time.setTextColor(Color.parseColor("#999999"));

}

holder.tv_amount.setTextColor(Color.LTGRAY);

}else {

//绑定数据

IncomeDetailsBean incomeDetailsBean = incomeDetails.get(position);

holder.barGraphItem.setRatio(incomeDetailsBean.getRatio());

holder.tv_time.setText(incomeDetailsBean.getDate());

holder.tv_amount.setText(incomeDetailsBean.getIncome());

holder.tv_amount.setTextColor(incomeDetailsBean.getRatio() == 0 ? Color.LTGRAY : context.getResources().getColor(R.color.colorAccent));

holder.iv_highest.setVisibility(incomeDetailsBean.isHighest() ? View.VISIBLE : View.INVISIBLE);

holder.tv_time.setTextSize(incomeDetailsBean.isHighest() ? 16 : 12);

holder.tv_time.setTextColor(incomeDetailsBean.isHighest() ? context.getResources().getColor(R.color.colorAccent) : Color.parseColor("#999999"));

}

//缩放动画(x轴方向不变,y轴由0到1增长效果)

Animation animation = AnimationUtils.loadAnimation(context, R.anim.scale_item);

holder.barGraphItem.startAnimation(animation);

}

纵向缩放动画

android:duration="700"

android:fromXScale="1.0"

android:fromYScale="0.0"

android:pivotY="100%"

android:toXScale="1.0"

android:toYScale="1.0">

最后是图中用到的配色资源

#3F51B5

#303F9F

@android:color/holo_green_dark

#3399cc00

#ff669900

#5099cc00

#0599cc00

#40669900

整个过程没有很生僻的点,基本是对Android Drawable、动画及简单自定义控件这些基本技能的综合运用。

希望对你有所帮助,喜欢记得点赞喔。

作者简介:现就职于甜橙金融信息技术部,负责安卓客户端开发工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值