国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android自定義View簡易折線圖控件(二)

2019-10-23 18:34:48
字體:
來源:轉載
供稿:網友

繼續(xù)練習自定義View,這次帶來的是簡易折線圖,支持坐標點點擊監(jiān)聽,效果如下:

Android,折線圖控件

畫坐標軸、畫刻度、畫點、連線。。x、y軸的數據范圍是寫死的 1 <= x <= 7 ,1 <= y <= 70 。。寫活的話涉及到坐標軸刻度的動態(tài)計算、坐標點的坐標修改,想想就頭大,這里只練習自定義View。

1、在res/values文件夾下新建attrs.xml文件,編寫自定義屬性:

<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="LineChartView"> <attr name="textColor" format="color" /> <attr name="lineColor" format="color" /> <attr name="pointColor" format="color" /> </declare-styleable></resources>

2、新建LineChartView繼承View,重寫構造方法:

 public LineChartView(Context context) {  this(context, null); } public LineChartView(Context context, AttributeSet attrs) {  this(context, attrs, 0); } public LineChartView(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr); }

3、在第三個構造方法中獲取自定義屬性的值:

 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LineChartView, defStyleAttr, 0); mTextColor = ta.getColor(R.styleable.LineChartView_textColor, 0xff381a59); mLineColor = ta.getColor(R.styleable.LineChartView_lineColor, 0xff8e29fa); mPointColor = ta.getColor(R.styleable.LineChartView_pointColor, 0xffff5100); mPointRadius = DensityUtils.dp2px(context, 3); ta.recycle();

4、創(chuàng)建畫圖所使用的對象,如Paint、Path:

 mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setColor(mTextColor); mTextPaint.setTextSize(40); mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mLinePaint.setStyle(Paint.Style.STROKE); mLinePaint.setColor(mLineColor); mLinePaint.setStrokeWidth(DensityUtils.dp2px(context, 2)); mLinePaint.setStrokeCap(Paint.Cap.ROUND); mXyPath = new Path(); mPointPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPointPaint.setStyle(Paint.Style.FILL); mPointPaint.setColor(mPointColor); mPointCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPointCirclePaint.setStyle(Paint.Style.STROKE); mPointCirclePaint.setStrokeWidth(DensityUtils.dp2px(context, 2)); mPointCirclePaint.setColor(mLineColor);

5、重寫onMeasure()方法,計算自定義View的寬高:

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  setMeasuredDimension(measuredDimension(widthMeasureSpec), measuredDimension(heightMeasureSpec)); } private int measuredDimension(int measureSpec) {  int result;  int mode = MeasureSpec.getMode(measureSpec);  int size = MeasureSpec.getSize(measureSpec);  if (mode == MeasureSpec.EXACTLY) {   result = size;  } else {   result = 500;   if (mode == MeasureSpec.AT_MOST) {    result = Math.min(result, size);   }  }  return result; }

6、暴露一個設置x、y數據集合的方法:

 /**  * 設置數據  *  * @param xList x軸數據集合  * @param yList y軸數據集合  */ public void setDataList(List<Integer> xList, List<Integer> yList) {  if (xList == null || yList == null || xList.size() == 0 || yList.size() == 0) {   throw new IllegalArgumentException("沒有數據");  }  if (xList.size() != yList.size()) {   throw new IllegalArgumentException("x、y軸數據長度不一致");  }  setPointData(xList, yList);  setPointAnimator(); } /**  * 設置坐標點的數據、坐標  *  * @param xList x軸數據集合  * @param yList y軸數據集合  */ private void setPointData(List<Integer> xList, List<Integer> yList) {  mPointList = new ArrayList<>();  for (int i = 0; i < xList.size(); i++) {   ChartPoint point = new ChartPoint();   //設置坐標點的xy數據   point.setxData(xList.get(i));   point.setyData(yList.get(i));   //計算坐標點的橫縱坐標   point.setX(xyMargin + xList.get(i) * (getWidth() - 2 * xyMargin) / maxX);   point.setY(getHeight() - xyMargin - (getHeight() - 2 * xyMargin) * yList.get(i) / maxY);   mPointList.add(point);  } } /**  * 設置坐標點移動的動畫  */ private void setPointAnimator() {  for (int i = 0; i < mPointList.size(); i++) {   final ChartPoint point = mPointList.get(i);   ValueAnimator anim;   if (mLastPointList != null && mLastPointList.size() > 0) {    anim = ValueAnimator.ofInt(mLastPointList.get(i).getY(), point.getY());   } else {    anim = ValueAnimator.ofInt(getHeight() - xyMargin, point.getY());   }   anim.setDuration(500);   anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    @Override    public void onAnimationUpdate(ValueAnimator animation) {     int value = (int) animation.getAnimatedValue();     point.setY(value);     invalidate();    }   });   anim.start();  }  //儲存坐標點集合  mLastPointList = mPointList; }

7、重寫onDraw()方法,繪制坐標軸、刻度,畫點連線,注意坐標的計算:

 @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  if (mPointList == null || mPointList.size() == 0) {   return;  }  mXyPath.reset();  mXyPath.moveTo(xyMargin, 0);  mXyPath.lineTo(xyMargin, getHeight() - xyMargin);  mXyPath.lineTo(getWidth(), getHeight() - xyMargin);  canvas.drawPath(mXyPath, mLinePaint);//畫x、y坐標軸  for (int i = 0; i < mPointList.size(); i++) {   //畫x軸刻度線   int x = xyMargin + (i + 1) * (getWidth() - 2 * xyMargin) / mPointList.size();   canvas.drawLine(x, getHeight() - xyMargin - graduatedLineLength, x, getHeight() - xyMargin, mLinePaint);   //畫y軸刻度線   int y = getHeight() - xyMargin - (i + 1) * (getHeight() - 2 * xyMargin) / mPointList.size();   canvas.drawLine(xyMargin, y, xyMargin + graduatedLineLength, y, mLinePaint);   //畫坐標軸刻度文本   canvas.drawText(String.valueOf(mPointList.get(i).getxData()), x, getHeight() - mTextPaint.getTextSize() / 4, mTextPaint);   canvas.drawText(String.valueOf((i + 1) * 10), 0, y + mTextPaint.getTextSize() / 2, mTextPaint);  }  //畫連接線  for (int i = 0; i < mPointList.size(); i++) {   if (i != mPointList.size() - 1) {    ChartPoint lastP = mPointList.get(i);    ChartPoint nextP = mPointList.get(i + 1);    canvas.drawLine(lastP.getX(), lastP.getY(), nextP.getX(), nextP.getY(), mLinePaint);   }  }  //畫坐標點  for (int i = 0; i < mPointList.size(); i++) {   ChartPoint point = mPointList.get(i);   canvas.drawCircle(point.getX(), point.getY(), mPointRadius, mPointPaint);   canvas.drawCircle(point.getX(), point.getY(), mPointRadius, mPointCirclePaint);  } }

8、設置坐標點點擊事件:

 private OnPointClickListener mOnPointClickListener; /**  * 坐標點點擊監(jiān)聽  */ public interface OnPointClickListener {  /**   * @param index 當前坐標點在數據集中的下標   * @param point 當前坐標點對象   */  void onPointClick(int index, ChartPoint point); } public void setOnPointClickListener(OnPointClickListener onPointClickListener) {  mOnPointClickListener = onPointClickListener; }

9、重寫onTouchEvent()方法,判斷當前點擊的點是不是在坐標點范圍內:

 @Override public boolean onTouchEvent(MotionEvent event) {  switch (event.getAction()) {   case MotionEvent.ACTION_DOWN:    //判斷當前點擊的點是否在坐標點范圍內    int curX = (int) event.getX();    int curY = (int) event.getY();    for (int i = 0; i < mPointList.size(); i++) {     ChartPoint point = mPointList.get(i);     double d1 = Math.pow(curX - point.getX(), 2);     double d2 = Math.pow(curY - point.getY(), 2);     //√ ̄(curX - cx)² + (curY - cy)² < R     if (Math.sqrt(d1 + d2) < mPointRadius + 10) {//為了方便點擊,把坐標點范圍增大了10像素      if (mOnPointClickListener != null) {       mOnPointClickListener.onPointClick(i, point);      }     }    }    break;  }  return super.onTouchEvent(event); }

10、在activity_main.xml布局文件中使用該View:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:lcv="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" tools:context=".MainActivity"> <com.monkey.linechartview.LineChartView  android:id="@+id/chartView"  android:layout_width="250dp"  android:layout_height="250dp"  android:layout_marginTop="@dimen/activity_vertical_margin"  lcv:lineColor="#8e29fa"  lcv:pointColor="#ff5100"  lcv:textColor="#000000" /> <Button  android:id="@+id/btn"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_marginTop="@dimen/activity_vertical_margin"  android:text="set data"  android:textAllCaps="false" /></LinearLayout>

11、在MainActivity.java中傳入數據集合,并設置坐標點點擊監(jiān)聽:

 btn.setOnClickListener(new View.OnClickListener() {  @Override  public void onClick(View v) {   List<Integer> xList = new ArrayList<>();   List<Integer> yList = new ArrayList<>();   for (int i = 0; i < 7; i++) {    xList.add(i + 1);    int y = (int) (Math.random() * 70 + 1);    yList.add(y);   }   chartView.setDataList(xList, yList);  } }); chartView.setOnPointClickListener(new LineChartView.OnPointClickListener() {  @Override  public void onPointClick(int position, ChartPoint point) {   tv.setText("position:" + position + "/nx:" + point.getxData() + "/ny:" + point.getyData());  }});

致此大致步驟完成了,發(fā)現和上一篇步驟差不多。。代碼已上傳github:
https://github.com/MonkeyMushroom/LineChartView/tree/master

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 唐山市| 城口县| 金湖县| 中宁县| 建水县| 荣昌县| 永善县| 玉屏| 收藏| 广安市| 西宁市| 东乡| 武平县| 嵊州市| 财经| 桂林市| 安丘市| 玛纳斯县| 宁明县| 石泉县| 乾安县| 巧家县| 墨竹工卡县| 榕江县| 舟曲县| 额敏县| 中方县| 普宁市| 安阳市| 青川县| 天全县| 江源县| 永胜县| 巴林左旗| 贵德县| 藁城市| 临泽县| 廊坊市| 朝阳县| 溆浦县| 绥滨县|