Android large screen chart MPAndroidChart horizontal histogram horizontal rounded histogram

//图表库
 implementation  'com.github.PhilJay:MPAndroidChart:v3.1.0'

X-axis: XAxis
Y-axis: YAxis
Legend: Legend
Description: Description
Limit line: LimitLine
Displayed view: MarkerView (it is displayed when selected)

The most important core function of MPAndroidChart

Many different chart types: LineChart (line chart), BarChart (bar chart, vertical, horizontal, stacked, grouped), PieChart (pie chart), ScatterChart (scatter chart), CandleStickChart (K-line chart, candle chart) , RadarChart (radar chart, spider chart), BubbleChart (bubble chart)
combined chart (eg, a line and a bar)
zoom on two axes (with touch gestures, individual axes or pinch zoom)
drag / pan (with touch gestures)
Separate (dual) y-axes
Highlight values ​​(with customizable popup view)
Save chart to SD card (as image)
Predefined color templates
Legend (autogenerated, customizable)
Customizable axes (x and y)
animations (build animations on x and y)
limit lines (provide additional info, max values, etc.)
listeners for touch, gesture and selection callbacks
fully customizable (drawing , fonts, legends, colors, backgrounds, dashed lines, etc.)
Supports Realm.io mobile database via MPAndroidChart-Realm library
Smooth rendering of up to 10.000 data points in Line-Chart and BarChart (tested on a 2014 OnePlus One running Android 6.0)
Lightweight (method count ~1.4K)
Available as a .jar file (only 500kb in size)
Available as a gradle dependency and
Google-PlayStore demo application via Maven
Widely used, great support for both GitHub and stackoverflow - mpandroidchart
is also available for iOS: Charts (the API works the same way)
is also available for Xamarin: MPAndroidChart. Xamarin has
limited support for dynamic and real-time data

horizontal histogram

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.github.mikephil.charting.charts.HorizontalBarChart
        android:id="@+id/chart1"
        android:layout_width="444px"
        android:layout_height="444px"
        android:background="@android:color/white" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="500px"
        android:orientation="horizontal">

        <Button
            android:id="@+id/actionToggleBarBorders"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="边框"></Button>

        <Button
            android:id="@+id/actionToggleValues"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="显示条形框的值"></Button>

        <Button
            android:id="@+id/actionToggleIcons"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="显示图标"></Button>

        <Button
            android:id="@+id/actionToggleHighlight"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="高亮显示"></Button>

        <Button
            android:id="@+id/actionTogglePinch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="手势"></Button>


    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="590px"
        android:orientation="horizontal">

        <Button
            android:id="@+id/actionToggleAutoScaleMinMax"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="比例"></Button>

        <Button
            android:id="@+id/animateX"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="X轴动画"></Button>

        <Button
            android:id="@+id/animateY"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Y轴动画"></Button>

        <Button
            android:id="@+id/animateXY"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="XY轴动画"></Button>

        <Button
            android:id="@+id/actionSave"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="保存"></Button>
    </LinearLayout>

    <SeekBar
        android:id="@+id/seekBar2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:layout_alignParentLeft="true"
        android:layout_alignParentBottom="true"
        android:layout_margin="8dp"
        android:layout_marginRight="5dp"
        android:layout_toLeftOf="@+id/tvYMax"
        android:max="200"
        android:paddingBottom="12dp" />

    <SeekBar
        android:id="@+id/seekBar1"
        android:layout_width="match_parent"
        android:visibility="gone"
        android:layout_height="wrap_content"
        android:layout_above="@+id/seekBar2"
        android:layout_margin="8dp"
        android:layout_marginRight="5dp"
        android:layout_marginBottom="35dp"
        android:layout_toLeftOf="@+id/tvXMax"
        android:max="500"
        android:paddingBottom="12dp" />

    <TextView
        android:id="@+id/tvXMax"
        android:layout_width="50dp"
        android:visibility="gone"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/seekBar1"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="15dp"
        android:gravity="right"
        android:text="@string/dash"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/tvYMax"
        android:visibility="gone"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/seekBar2"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="15dp"
        android:gravity="right"
        android:text="@string/dash"
        android:textAppearance="?android:attr/textAppearanceMedium" />

</RelativeLayout>

package com.xxmassdeveloper.mpchartexample;import com.sbas.xueliapplication.R;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.RectF;
import android.net.Uri;
import android.os.Bundle;
import androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.XAxis.XAxisPosition;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.MPPointF;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;

import java.util.ArrayList;
import java.util.List;

public class HorizontalBarChartActivity extends DemoBase implements
        OnChartValueSelectedListener, View.OnClickListener {

    private HorizontalBarChart chart;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_horizontalbarchart);

        setTitle("HorizontalBarChartActivity");



        chart = findViewById(R.id.chart1);
        chart.setOnChartValueSelectedListener(this);
        // chart.setHighlightEnabled(false);

        chart.setDrawBarShadow(false);

        chart.setDrawValueAboveBar(true);

        chart.getDescription().setEnabled(false);

        // if more than 60 entries are displayed in the chart, no values will be
        // drawn
        chart.setMaxVisibleValueCount(60);

        // scaling can now only be done on x- and y-axis separately
        chart.setPinchZoom(false);

        // draw shadows for each bar that show the maximum value
        // chart.setDrawBarShadow(true);

        chart.setDrawGridBackground(false);

        XAxis xl = chart.getXAxis();
        xl.setPosition(XAxisPosition.BOTTOM);
        xl.setTypeface(tfLight);
        xl.setDrawAxisLine(true);
        xl.setDrawGridLines(false);
        xl.setGranularity(10f);

        YAxis yl = chart.getAxisLeft();
        yl.setTypeface(tfLight);
        yl.setDrawAxisLine(true);
        yl.setDrawGridLines(true);
        yl.setAxisMinimum(0f); // this replaces setStartAtZero(true)
//        yl.setInverted(true);

        YAxis yr = chart.getAxisRight();
        yr.setTypeface(tfLight);
        yr.setDrawAxisLine(true);
        yr.setDrawGridLines(false);
        yr.setAxisMinimum(0f); // this replaces setStartAtZero(true)
//        yr.setInverted(true);

        chart.setFitBars(true);
        chart.animateY(2500);

        // setting data
        setDataHorizontalBarChar(5,50);

        Legend l = chart.getLegend();
        l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
        l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
        l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
        l.setDrawInside(false);
        l.setFormSize(8f);
        l.setXEntrySpace(4f);

        initButton();
    }

    private void initButton() {
        Button actionToggleBarBorders =  findViewById(R.id.actionToggleBarBorders);
        actionToggleBarBorders.setOnClickListener(this::onClick);
        Button actionToggleValues =  findViewById(R.id.actionToggleValues);
        actionToggleValues.setOnClickListener(this::onClick);
        Button actionToggleIcons =  findViewById(R.id.actionToggleIcons);
        actionToggleIcons.setOnClickListener(this::onClick);
        Button actionToggleHighlight =  findViewById(R.id.actionToggleHighlight);
        actionToggleHighlight.setOnClickListener(this::onClick);
        Button actionTogglePinch =  findViewById(R.id.actionTogglePinch);
        actionTogglePinch.setOnClickListener(this::onClick);
        Button actionToggleAutoScaleMinMax =  findViewById(R.id.actionToggleAutoScaleMinMax);
        actionToggleAutoScaleMinMax.setOnClickListener(this::onClick);
        Button animateX =  findViewById(R.id.animateX);
        animateX.setOnClickListener(this::onClick);
        Button animateY =  findViewById(R.id.animateY);
        animateY.setOnClickListener(this::onClick);
        Button animateXY =  findViewById(R.id.animateXY);
        animateXY.setOnClickListener(this::onClick);
        Button actionSave =  findViewById(R.id.actionSave);
        actionSave.setOnClickListener(this::onClick);


    }

    private void setDataHorizontalBarChar(int count, float range) {

        float barWidth = 9f;
        float spaceForBar = 10f;
        ArrayList<BarEntry> values = new ArrayList<>();

        for (int i = 0; i < count; i++) {
            float val = (float) (Math.random() * range);
            values.add(new BarEntry(i * spaceForBar, val,
                    getResources().getDrawable(R.drawable.star)));
        }

        BarDataSet set1;

        if (chart.getData() != null &&
                chart.getData().getDataSetCount() > 0) {
            set1 = (BarDataSet) chart.getData().getDataSetByIndex(0);
            set1.setValues(values);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
        } else {
            set1 = new BarDataSet(values, "DataSet 1");

            set1.setDrawIcons(false);

            ArrayList<IBarDataSet> dataSets = new ArrayList<>();
            dataSets.add(set1);

            BarData data = new BarData(dataSets);
            data.setValueTextSize(10f);
            data.setValueTypeface(tfLight);
            data.setBarWidth(barWidth);
            chart.setData(data);
        }
    }



    @Override
    protected void saveToGallery() {
        saveToGallery(chart, "HorizontalBarChartActivity");
    }


    private final RectF mOnValueSelectedRectF = new RectF();

    @Override
    public void onValueSelected(Entry e, Highlight h) {

        if (e == null)
            return;

        RectF bounds = mOnValueSelectedRectF;
        chart.getBarBounds((BarEntry) e, bounds);

        MPPointF position = chart.getPosition(e, chart.getData().getDataSetByIndex(h.getDataSetIndex())
                .getAxisDependency());

        Log.i("bounds", bounds.toString());
        Log.i("position", position.toString());

        MPPointF.recycleInstance(position);
    }

    @Override
    public void onNothingSelected() {}

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.viewGithub: {
                Intent i = new Intent(Intent.ACTION_VIEW);
                i.setData(Uri.parse("https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartExample/src/com/xxmassdeveloper/mpchartexample/HorizontalBarChartActivity.java"));
                startActivity(i);
                break;
            }
            case R.id.actionToggleValues: {
                List<IBarDataSet> sets = chart.getData()
                        .getDataSets();

                for (IBarDataSet iSet : sets) {
                    iSet.setDrawValues(!iSet.isDrawValuesEnabled());
                }
                chart.invalidate();
                break;
            }
            case R.id.actionToggleIcons: {
                List<IBarDataSet> sets = chart.getData()
                        .getDataSets();

                for (IBarDataSet iSet : sets) {
                    iSet.setDrawIcons(!iSet.isDrawIconsEnabled());
                }

                chart.invalidate();
                break;
            }
            case R.id.actionToggleHighlight: {
                if(chart.getData() != null) {
                    chart.getData().setHighlightEnabled(!chart.getData().isHighlightEnabled());
                    chart.invalidate();
                }
                break;
            }
            case R.id.actionTogglePinch: {
                if (chart.isPinchZoomEnabled())
                    chart.setPinchZoom(false);
                else
                    chart.setPinchZoom(true);

                chart.invalidate();
                break;
            }
            case R.id.actionToggleAutoScaleMinMax: {
                chart.setAutoScaleMinMaxEnabled(!chart.isAutoScaleMinMaxEnabled());
                chart.notifyDataSetChanged();
                break;
            }
            case R.id.actionToggleBarBorders: {
                for (IBarDataSet set : chart.getData().getDataSets())
                    ((BarDataSet)set).setBarBorderWidth(set.getBarBorderWidth() == 1.f ? 0.f : 1.f);

                chart.invalidate();
                break;
            }
            case R.id.animateX: {
                chart.animateX(2000);
                break;
            }
            case R.id.animateY: {
                chart.animateY(2000);
                break;
            }
            case R.id.animateXY: {
                chart.animateXY(2000, 2000);
                break;
            }
            case R.id.actionSave: {
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                    saveToGallery();
                } else {
                    requestStoragePermission(chart);
                }
                break;
            }
        }
    }
}

package com.xxmassdeveloper.mpchartexample.notimportant;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.view.View;
import android.widget.Toast;

import com.github.mikephil.charting.charts.Chart;
import com.sbas.xueliapplication.R;

/**
 * Base class of all Activities of the Demo Application.
 *
 * @author Philipp Jahoda
 */
public abstract class DemoBase extends AppCompatActivity implements ActivityCompat.OnRequestPermissionsResultCallback {

    protected final String[] months = new String[] {
            "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"
    };

    protected final String[] parties = new String[] {
            "Party A", "Party B", "Party C", "Party D", "Party E", "Party F", "Party G", "Party H",
            "Party I", "Party J", "Party K", "Party L", "Party M", "Party N", "Party O", "Party P",
            "Party Q", "Party R", "Party S", "Party T", "Party U", "Party V", "Party W", "Party X",
            "Party Y", "Party Z"
    };

    private static final int PERMISSION_STORAGE = 0;

    protected Typeface tfRegular;
    protected Typeface tfLight;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        tfRegular = Typeface.createFromAsset(getAssets(), "OpenSans-Regular.ttf");
        tfLight = Typeface.createFromAsset(getAssets(), "OpenSans-Light.ttf");
    }

    protected float getRandom(float range, float start) {
        return (float) (Math.random() * range) + start;
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        overridePendingTransition(R.anim.move_left_in_activity, R.anim.move_right_out_activity);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_STORAGE) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                saveToGallery();
            } else {
                Toast.makeText(getApplicationContext(), "Saving FAILED!", Toast.LENGTH_SHORT)
                        .show();
            }
        }
    }

    protected void requestStoragePermission(View view) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            Snackbar.make(view, "Write permission is required to save image to gallery", Snackbar.LENGTH_INDEFINITE)
                    .setAction(android.R.string.ok, new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            ActivityCompat.requestPermissions(DemoBase.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_STORAGE);
                        }
                    }).show();
        } else {
            Toast.makeText(getApplicationContext(), "Permission Required!", Toast.LENGTH_SHORT)
                    .show();
            ActivityCompat.requestPermissions(DemoBase.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_STORAGE);
        }
    }

    protected void saveToGallery(Chart chart, String name) {
        if (chart.saveToGallery(name + "_" + System.currentTimeMillis(), 70))
            Toast.makeText(getApplicationContext(), "Saving SUCCESSFUL!",
                    Toast.LENGTH_SHORT).show();
        else
            Toast.makeText(getApplicationContext(), "Saving FAILED!", Toast.LENGTH_SHORT)
                    .show();
    }

    protected abstract void saveToGallery();
}

 If you don't want the line above yl.setEnabled(false);

        YAxis yl = chart.getAxisLeft();
        yl.setEnabled(false);
        yl.setTypeface(tfLight);
        yl.setDrawAxisLine(true);
        yl.setDrawGridLines(false);
        yl.setAxisMinimum(0f); // this replaces setStartAtZero(true)
//        yl.setInverted(true);

If you want a rounded histogram modify

HorizontalBarChartRenderer.java

 

 

            if (isCustomFill) {
                dataSet.getFill(pos)
                        .fillRect(
                                c, mRenderPaint,
                                buffer.buffer[j],
                                buffer.buffer[j + 1],
                                buffer.buffer[j + 2],
                                buffer.buffer[j + 3],
                                isInverted ? Fill.Direction.LEFT : Fill.Direction.RIGHT);
            }
            else {
//                c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
//                        buffer.buffer[j + 3], mRenderPaint);
                RectF rectF=new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],buffer.buffer[j + 3]);
                c.drawRoundRect(rectF,(float)25,(float)25,mRenderPaint);

            }

However, if you want to customize the radians of the four corners, you need to use the Path class to draw. Make the following changes: 

HorizontalBarChartRenderer.java

            if (isCustomFill) {
                dataSet.getFill(pos)
                        .fillRect(
                                c, mRenderPaint,
                                buffer.buffer[j],
                                buffer.buffer[j + 1],
                                buffer.buffer[j + 2],
                                buffer.buffer[j + 3],
                                isInverted ? Fill.Direction.LEFT : Fill.Direction.RIGHT);
            }
            else {
//                c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
//                        buffer.buffer[j + 3], mRenderPaint);
//                RectF rectF=new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],buffer.buffer[j + 3]);
//                c.drawRoundRect(rectF,(float)25,(float)25,mRenderPaint);
                RectF rectF=new RectF(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],buffer.buffer[j + 3]);
                Path path = new Path();
               //float数组中4个角分别是左上、右上、右下、左下
                path.addRoundRect(rectF,new float[]{0, 0, 20, 20, 20, 20, 0, 0},Path.Direction.CCW);
                c.drawPath(path,mRenderPaint);

            }

 

 

Adjust the width of the graph.

 

 

Guess you like

Origin blog.csdn.net/sun6223508/article/details/127190514
Recommended