java - MPAndroidChart moveViewToX 并不总是有效
问题描述
我正在实现分页解决方案并在到达图表左侧时加载数据(使用 setOnChartGestureListener),数据以相反的顺序显示(x 值为负)。加载新的数据集后,视口应该跳转到第一个加载的条目,但是 moveViewToX 方法有时会给出不稳定的行为并且不会移动视口。
我尝试了不同的技巧,比如延迟的 moveViewToX,从其他地方调用 moveViewToX,甚至向调用 moveViewToX 的活动添加一个按钮也不起作用。
我搜索了stackoverflow,发现了一个与moveViewToX相关的类似问题,但没有解决问题(HorizontalBarChart moveViewToX 不起作用)。
我正在使用这个版本的 MPAndroidChart
com.github.PhilJay:MPAndroidChart:v3.1.0
为了重现行为,我将代码减少到最低限度。
activity_device_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingTop="@dimen/keyline_5">
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/chart"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
ChartTestActivity.java
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.MotionEvent;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.ChartTouchListener;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.utils.EntryXComparator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import androidx.appcompat.app.AppCompatActivity;
import es.arpa.sensor.iot.R;
public class ChartTestActivity extends AppCompatActivity {
private final static String TAG = ChartTestActivity.class.getSimpleName();
private final static int ENTRIES_PER_PAGE = 100;
private LineChart mChart;
private int mPageCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device_graph);
mChart = (LineChart) findViewById(R.id.chart);
initChart();
getData(mPageCount);
}
private void initChart() {
mChart.setBackgroundColor(Color.WHITE);
mChart.getDescription().setEnabled(false);
mChart.setDrawGridBackground(false);
mChart.setScaleYEnabled(false);
mChart.setExtraBottomOffset(20);
// X-Axis Style
XAxis xAxis = mChart.getXAxis();
xAxis.enableGridDashedLine(10f, 10f, 0f);
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
// Y-Axis Style
YAxis yAxis = mChart.getAxisLeft();
yAxis.enableGridDashedLine(10f, 10f, 0f);
yAxis.setAxisMinimum(0);
yAxis.setAxisMaximum(20);
mChart.getAxisRight().setEnabled(false);
// Create a dataset
ArrayList<Entry> values = new ArrayList<>();
LineDataSet set = new LineDataSet(values, "TEST");
set.setLineWidth(3f);
set.setColor(getColor(R.color.purple_200));
set.setDrawCircles(false);
// Hide data point values
set.setDrawValues(false);
// Selection indicator
set.setHighLightColor(Color.RED);
set.setHighlightLineWidth(1f);
// Customize legend entry
set.setForm(Legend.LegendForm.LINE);
set.setFormLineWidth(3f);
set.setFormSize(30.f);
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(set);
LineData data = new LineData(dataSets);
mChart.setData(data);
mChart.setOnChartGestureListener(new OnChartGestureListener() {
@Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
}
@Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
if (mChart.getLowestVisibleX() == mChart.getXAxis().getAxisMinimum())
getData(mPageCount++);
}
@Override
public void onChartLongPressed(MotionEvent me) {
}
@Override
public void onChartDoubleTapped(MotionEvent me) {
}
@Override
public void onChartSingleTapped(MotionEvent me) {
}
@Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
}
@Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
}
@Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {
}
});
}
private void getData(int page) {
LoadDataAsyncTask task = new LoadDataAsyncTask(new LoadDataListener<List<Entry>>() {
@Override
public void taskFinished(List<Entry> result) {
ListIterator it = result.listIterator();
LineDataSet set = (LineDataSet) mChart.getData().getDataSetByIndex(0);
Entry jumpTo = null;
while (it.hasNext()) {
Entry entry = (Entry) it.next();
set.addEntry(entry);
if (jumpTo == null)
jumpTo = entry;
}
Collections.sort(set.getValues(), new EntryXComparator());
set.notifyDataSetChanged();
mChart.getData().notifyDataChanged();
mChart.notifyDataSetChanged();
mChart.invalidate();
mChart.setVisibleXRangeMaximum(50);
mChart.setVisibleXRangeMinimum(10);
// This statement should jump at the beginning of the added entries
mChart.moveViewToX(jumpTo.getX());
}
});
task.execute(page);
}
public interface LoadDataListener<T> {
void taskFinished(T result);
}
public class LoadDataAsyncTask extends AsyncTask<Integer, Void, List<Entry>> {
private LoadDataListener mListener;
public LoadDataAsyncTask(LoadDataListener loadDataListener) {
mListener = loadDataListener;
}
@Override
protected List<Entry> doInBackground(Integer... params) {
List<Entry> values = new ArrayList<>();
int page = params[0];
for (int i = 0; i < ENTRIES_PER_PAGE; i++) {
int xValue = -(i + (page * ENTRIES_PER_PAGE));
int yValue = page;
values.add(new Entry(xValue, yValue));
}
return values;
}
@Override
protected void onPostExecute(List<Entry> result) {
super.onPostExecute(result);
if (mListener != null)
mListener.taskFinished(result);
}
}
}
任何帮助将不胜感激,谢谢
解决方案
可靠的工作解决方案,不会永久禁用投掷:
禁用拖动减速并调度触摸事件(以取消可能的现有甩动):
isDragDecelerationEnabled = false dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 0f, 0f, 0))
设置数据等
移动视图并安排作业以重新启用拖动减速
moveViewToX(10f) postDelayed({ isDragDecelerationEnabled = true}, 100L)
这可确保在移动视图的作业完成后拖动减速运行。
使用动画版本 (moveViewToAnimated) 时,需要相应地调整延迟。
该解决方案并不是最优雅的,因为使用预定作业永远不会 100% 准确。
推荐阅读
- python - tkinter 文本插入 wordstart 的问题
- php - 创建自定义用户电子邮件
- c - 如何编译 C 程序,使二进制文件仅在不同的返回值上有所不同?
- python - 模块“accounts.views”没有属性“signup”
- python - 我想从简历中提取特定部分
- mariadb - 如何在运行单元测试时启动 mariadb
- jquery - 剑道下拉列表值未通过
- firebase - Google sign in working on emulator but not on Android device flutter
- header - 滚动时如何使内容不在固定导航栏下方?
- jupyter-notebook - 使图像网格框可滚动