欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

android實現(xiàn)可以滑動的平滑曲線圖

 更新時間:2022年06月29日 15:38:22   作者:songdongpancsdn  
這篇文章主要為大家詳細介紹了android實現(xiàn)可以滑動的平滑曲線圖,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了android實現(xiàn)可以滑動的平滑曲線圖的具體代碼,供大家參考,具體內(nèi)容如下

直接上代碼,里面有詳細注解

1 attr 屬性編寫   

<!-- xy坐標(biāo)軸顏色 -->

<attr name="xy_line_color" format="color" />
? ? <!-- xy坐標(biāo)軸寬度 -->
? ? <attr name="xy_line_width" format="dimension" />
? ? <!-- xy坐標(biāo)軸文字顏色 -->
? ? <attr name="xy_text_color" format="color" />
? ? <!-- xy坐標(biāo)軸文字大小 -->
? ? <attr name="xy_text_size" format="dimension" />
? ? <!-- 折線圖中折線的顏色 -->
? ? <attr name="line_color" format="color" />
? ? <!-- x軸各個坐標(biāo)點水平間距 -->
? ? <attr name="interval" format="dimension" />
? ? <!-- 背景顏色 -->
? ? <attr name="bg_color" format="color" />
? ? <!-- 曲線選中外部顏色 -->
? ? <attr name="select_circle_color" format="color" />
? ? <!-- 曲線選中內(nèi)部顏色 -->
? ? <attr name="select_reminder_color" format="color" />
? ? <!--是否抬手滾動-->
? ? <attr name="isScroll" format="boolean" />
? ? <declare-styleable name="ChartView">
? ? ? ? <attr name="xy_line_color" />
? ? ? ? <attr name="xy_line_width" />
? ? ? ? <attr name="xy_text_color" />
? ? ? ? <attr name="xy_text_size" />
? ? ? ? <attr name="line_color" />
? ? ? ? <attr name="interval" />
? ? ? ? <attr name="bg_color" />
? ? ? ? <attr name="select_circle_color" />
? ? ? ? <attr name="select_reminder_color" />
? ? ? ? <attr name="isScroll" />
? ? ? ? <!--提示框跟滑動顯示的位置-->
? ? ? ? <attr name="show_position">
? ? ? ? ? ? <enum name="first" value="1" />
? ? ? ? ? ? <enum name="middle" value="2" />
? ? ? ? ? ? <enum name="end" value="3" />
? ? ? ? </attr>
</declare-styleable>

2 ChartView

package com.laisontech.commonuilibrary.customviews;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import com.laisontech.commonuilibrary.R;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
?* 自定義折線圖
?*/
public class ChartView extends View {
? ? private static final int FIRST = 1;
? ? private static final int MIDDLE = 2;
? ? private static final int END = 3;
? ? //xy坐標(biāo)軸顏色
? ? private int xyLineColor = 0xffCFE2CF;
? ? //折線選中的圓形顏色
? ? private int selectCircleColor = 0xff00A8FF;
? ? //選中數(shù)據(jù)提示框顏色
? ? private int selectReminderColor = 0xff00A8FF;
? ? //折線中圓形內(nèi)部部顏色
? ? private int xyTextColor = 0xff0014FF;
? ? //折線圖中折線的顏色
? ? private int lineColor = 0xffFD00FF;
? ? //xy坐標(biāo)軸寬度
? ? private int xyLineWidth = dpToPx(1);
? ? //xy坐標(biāo)軸文字大小
? ? private int xyTextSize = spToPx(12);
? ? //x軸各個坐標(biāo)點水平間距
? ? private int interval = dpToPx(40);
? ? //背景顏色
? ? private int bgColor = 0xffffffff;
? ? //是否有起手時的滑動感
? ? private boolean isScroll = false;
? ? //提示框顯示位置
? ? private int mShowPositionType = 3;
? ? //繪制XY軸坐標(biāo)對應(yīng)的畫筆
? ? private Paint mXYPaint;
? ? //繪制XY軸的文本對應(yīng)的畫筆
? ? private Paint mXYTextPaint;
? ? //畫折線對應(yīng)的畫筆
? ? private Paint mSpinnerLinePaint;
? ? private int width;
? ? private int height;
? ? //x軸的原點坐標(biāo)
? ? private int mXOri;
? ? //y軸的原點坐標(biāo)
? ? private int mYOri;
? ? //第一個點X的坐標(biāo)
? ? private float mXInit;
? ? //第一個點對應(yīng)的最大X坐標(biāo)
? ? private float maxXInit;
? ? //第一個點對應(yīng)的最小X坐標(biāo)
? ? private float minXInit;
? ? //x軸坐標(biāo)對應(yīng)的數(shù)據(jù)
? ? private List<String> mXData = new ArrayList<>();
? ? //y軸坐標(biāo)對應(yīng)的數(shù)據(jù)
? ? private List<Integer> mYData = new ArrayList<>();
? ? //折線對應(yīng)的數(shù)據(jù)
? ? private Map<String, Integer> mSpinnerValue = new HashMap<>();
? ? //點擊的點對應(yīng)的X軸的第幾個點,默認(rèn)1
? ? private int selectIndex = 1;
? ? //X軸刻度文本對應(yīng)的最大矩形,為了選中時,在x軸文本畫的框框大小一致,獲取從數(shù)據(jù)中得到的x軸數(shù)據(jù),獲得最長數(shù)據(jù)
? ? private Rect xValueRect;
? ? //速度檢測器
? ? private VelocityTracker mTracker;
? ? //是否為短距離滑動
? ? private boolean isShortSlide = false;
? ? //獲取尺寸的的中間
? ? private int mSelectMiddle = 0;
? ? //曲線切率
? ? private float mLineSmoothness = 0.18f;

? ? public ChartView(Context context) {
? ? ? ? this(context, null);
? ? }

? ? public ChartView(Context context, AttributeSet attrs) {
? ? ? ? this(context, attrs, 0);
? ? }

? ? public ChartView(Context context, AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? ? ? init(context, attrs, defStyleAttr);
? ? ? ? initPaint();
? ? }

? ? //設(shè)置切率
? ? public void setLineSmoothness(float lineSmoothness) {
? ? ? ? if (lineSmoothness != this.mLineSmoothness) {
? ? ? ? ? ? this.mLineSmoothness = lineSmoothness;
? ? ? ? }
? ? }

? ? /**
? ? ?* 初始化
? ? ?*/
? ? private void initPaint() {
? ? ? ? mXYPaint = new Paint();
? ? ? ? mXYPaint.setAntiAlias(true);
? ? ? ? mXYPaint.setStrokeWidth(xyLineWidth);
? ? ? ? mXYPaint.setStrokeJoin(Paint.Join.ROUND);
? ? ? ? mXYPaint.setColor(xyLineColor);

? ? ? ? mXYTextPaint = new Paint();
? ? ? ? mXYTextPaint.setAntiAlias(true);
? ? ? ? mXYTextPaint.setTextSize(xyTextSize);
? ? ? ? mXYTextPaint.setStrokeJoin(Paint.Join.ROUND);
? ? ? ? mXYTextPaint.setColor(xyTextColor);
? ? ? ? mXYTextPaint.setStyle(Paint.Style.STROKE);

? ? ? ? mSpinnerLinePaint = new Paint();
? ? ? ? mSpinnerLinePaint.setAntiAlias(true);
? ? ? ? mSpinnerLinePaint.setStrokeWidth(xyLineWidth);
? ? ? ? mSpinnerLinePaint.setColor(lineColor);
? ? ? ? mSpinnerLinePaint.setStyle(Paint.Style.STROKE);
? ? ? ? mSpinnerLinePaint.setStrokeJoin(Paint.Join.ROUND);
? ? }

? ? /**
? ? ?* 初始化
? ? ?*
? ? ?* @param context
? ? ?* @param attrs
? ? ?* @param defStyleAttr
? ? ?*/
? ? private void init(Context context, AttributeSet attrs, int defStyleAttr) {
? ? ? ? TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ChartView, defStyleAttr, 0);
? ? ? ? int count = array.getIndexCount();
? ? ? ? for (int i = 0; i < count; i++) {
? ? ? ? ? ? int attr = array.getIndex(i);
? ? ? ? ? ? if (attr == R.styleable.ChartView_xy_line_color) {
? ? ? ? ? ? ? ? xyLineColor = array.getColor(attr, xyLineColor);

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_xy_line_width) {
? ? ? ? ? ? ? ? xyLineWidth = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xyLineWidth, getResources().getDisplayMetrics()));

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_xy_text_color) {
? ? ? ? ? ? ? ? xyTextColor = array.getColor(attr, xyTextColor);

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_xy_text_size) {
? ? ? ? ? ? ? ? xyTextSize = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xyTextSize, getResources().getDisplayMetrics()));

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_line_color) {
? ? ? ? ? ? ? ? lineColor = array.getColor(attr, lineColor);

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_interval) {
? ? ? ? ? ? ? ? interval = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, interval, getResources().getDisplayMetrics()));

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_bg_color) {
? ? ? ? ? ? ? ? bgColor = array.getColor(attr, bgColor);

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_select_circle_color) {
? ? ? ? ? ? ? ? selectCircleColor = array.getColor(attr, selectCircleColor);

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_select_reminder_color) {
? ? ? ? ? ? ? ? selectReminderColor = array.getColor(attr, selectReminderColor);

? ? ? ? ? ? } else if (attr == R.styleable.ChartView_isScroll) {
? ? ? ? ? ? ? ? isScroll = array.getBoolean(attr, isScroll);
? ? ? ? ? ? } else if (attr == R.styleable.ChartView_show_position) {
? ? ? ? ? ? ? ? mShowPositionType = array.getInt(attr, mShowPositionType);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? array.recycle();
? ? }

? ? @Override
? ? protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
? ? ? ? if (changed) {
? ? ? ? ? ? width = getWidth();
? ? ? ? ? ? height = getHeight();
? ? ? ? ? ? //Y軸文本的最大寬度
? ? ? ? ? ? float textYWdith = getTextBounds(mYData.get(getListItemMaxIndex(mYData)) + "", mXYTextPaint).width();
? ? ? ? ? ? for (int i = 0; i < mYData.size(); i++) {//求取y軸文本最大的寬度
? ? ? ? ? ? ? ? float temp = getTextBounds(mYData.get(i) + "", mXYTextPaint).width();
? ? ? ? ? ? ? ? if (temp > textYWdith)
? ? ? ? ? ? ? ? ? ? textYWdith = temp;
? ? ? ? ? ? }
? ? ? ? ? ? int dp2 = dpToPx(2);
? ? ? ? ? ? int dp3 = dpToPx(3);
? ? ? ? ? ? mXOri = (int) (dp2 + textYWdith + dp2 + xyLineWidth);
? ? ? ? ? ? //獲取x軸的最長文本的寬度所占的矩形
? ? ? ? ? ? xValueRect = getTextBounds(mXData.get(getListItemMaxIndex(mXData)), mXYTextPaint);
? ? ? ? ? ? //X軸文本高度
? ? ? ? ? ? float textXHeight = xValueRect.height();
? ? ? ? ? ? for (int i = 0; i < mXData.size(); i++) {
? ? ? ? ? ? ? ? Rect rect = getTextBounds(mXData.get(i) + "", mXYTextPaint);
? ? ? ? ? ? ? ? if (rect.height() > textXHeight)
? ? ? ? ? ? ? ? ? ? textXHeight = rect.height();
? ? ? ? ? ? ? ? if (rect.width() > xValueRect.width())
? ? ? ? ? ? ? ? ? ? xValueRect = rect;
? ? ? ? ? ? }
? ? ? ? ? ? mYOri = (int) (height - dp2 - textXHeight - dp3 - xyLineWidth);
? ? ? ? ? ? mXInit = mXOri + xValueRect.width() / 2 + dpToPx(5);
? ? ? ? ? ? minXInit = width - (width - mXOri) * 0.1f - interval * (mXData.size() - 1);
? ? ? ? ? ? maxXInit = mXInit;
? ? ? ? }
? ? ? ? selectIndex = getSelectIndexFromShowType(mShowPositionType);
? ? ? ? super.onLayout(changed, left, top, right, bottom);
? ? }

? ? @Override
? ? protected void onDraw(Canvas canvas) {
? ? ? ? canvas.drawColor(bgColor);
? ? ? ? drawXY(canvas);
? ? ? ? drawBrokenLineAndPoint(canvas);
? ? }

? ? /**
? ? ?* 繪制交點處對應(yīng)的點
? ? ?*/
? ? private void drawBrokenLineAndPoint(Canvas canvas) {
? ? ? ? if (mXData.size() <= 0)
? ? ? ? ? ? return;
? ? ? ? int layerId = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);
? ? ? ? drawBrokenLine(canvas);
? ? ? ? drawBrokenPoint(canvas);
? ? ? ? // 將超出x軸坐標(biāo)的部分截掉
? ? ? ? mSpinnerLinePaint.setStyle(Paint.Style.FILL);
? ? ? ? mSpinnerLinePaint.setColor(bgColor);
? ? ? ? mSpinnerLinePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
? ? ? ? RectF rectF = new RectF(0, 0, mXOri, height);
? ? ? ? canvas.drawRect(rectF, mSpinnerLinePaint);
? ? ? ? mSpinnerLinePaint.setXfermode(null);

? ? ? ? canvas.restoreToCount(layerId);
? ? }

? ? /**
? ? ?* 繪制曲線對應(yīng)的點
? ? ?*/
? ? private void drawBrokenPoint(Canvas canvas) {
? ? ? ? float dp2 = dpToPx(2);
? ? ? ? float dp4 = dpToPx(4);
? ? ? ? float dp7 = dpToPx(7);
? ? ? ? Log.e("selectIndex", "index:" + selectIndex);
? ? ? ? //繪制節(jié)點
? ? ? ? for (int i = 0; i < mXData.size(); i++) {
? ? ? ? ? ? float x = mXInit + interval * i;
? ? ? ? ? ? float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(i)) / mYData.get(mYData.size() - 1);
? ? ? ? ? ? //繪制選中點
? ? ? ? ? ? if (i == selectIndex - 1) {
? ? ? ? ? ? ? ? mSpinnerLinePaint.setStyle(Paint.Style.FILL);
? ? ? ? ? ? ? ? //設(shè)置選中顏色
? ? ? ? ? ? ? ? mSpinnerLinePaint.setColor(selectCircleColor);
? ? ? ? ? ? ? ? canvas.drawCircle(x, y, dp7, mSpinnerLinePaint);
? ? ? ? ? ? ? ? mSpinnerLinePaint.setColor(selectReminderColor);
? ? ? ? ? ? ? ? canvas.drawCircle(x, y, dp4, mSpinnerLinePaint);
? ? ? ? ? ? ? ? drawFloatTextBox(canvas, x, y - dp7, mSpinnerValue.get(mXData.get(i)));
? ? ? ? ? ? }
? ? ? ? ? ? //繪制普通節(jié)點
? ? ? ? ? ? mSpinnerLinePaint.setStyle(Paint.Style.FILL);
? ? ? ? ? ? mSpinnerLinePaint.setColor(Color.WHITE);
? ? ? ? ? ? canvas.drawCircle(x, y, dp2, mSpinnerLinePaint);
? ? ? ? ? ? mSpinnerLinePaint.setStyle(Paint.Style.STROKE);
? ? ? ? ? ? mSpinnerLinePaint.setColor(lineColor);
? ? ? ? ? ? canvas.drawCircle(x, y, dp2, mSpinnerLinePaint);

? ? ? ? }
? ? }

? ? /**
? ? ?* 繪制浮動框
? ? ?* */
? ? private void drawFloatTextBox(Canvas canvas, float x, float y, int text) {
? ? ? ? int dp6 = dpToPx(6);
? ? ? ? int dp18 = dpToPx(18);
? ? ? ? //p1
? ? ? ? Path path = new Path();
? ? ? ? path.moveTo(x, y);
? ? ? ? //p2
? ? ? ? path.lineTo(x - dp6, y - dp6);
? ? ? ? //p3
? ? ? ? path.lineTo(x - dp18, y - dp6);
? ? ? ? //p4
? ? ? ? path.lineTo(x - dp18, y - dp6 - dp18);
? ? ? ? //p5
? ? ? ? path.lineTo(x + dp18, y - dp6 - dp18);
? ? ? ? //p6
? ? ? ? path.lineTo(x + dp18, y - dp6);
? ? ? ? //p7
? ? ? ? path.lineTo(x + dp6, y - dp6);
? ? ? ? //p1
? ? ? ? path.lineTo(x, y);
? ? ? ? canvas.drawPath(path, mSpinnerLinePaint);
? ? ? ? mSpinnerLinePaint.setColor(Color.WHITE);
? ? ? ? mSpinnerLinePaint.setTextSize(spToPx(14));
? ? ? ? Rect rect = getTextBounds(text + "", mSpinnerLinePaint);
? ? ? ? canvas.drawText(text + "", x - rect.width() / 2, y - dp6 - (dp18 - rect.height()) / 2, mSpinnerLinePaint);
? ? }

? ? /**
? ? ?* 繪制平滑曲線
? ? ?*/
? ? private void drawBrokenLine(Canvas canvas) {
? ? ? ? mSpinnerLinePaint.setStyle(Paint.Style.STROKE);
? ? ? ? mSpinnerLinePaint.setColor(lineColor);
? ? ? ? //繪制折線
? ? ? ? Path path = new Path();
? ? ? ? float prePreviousPointX = Float.NaN;
? ? ? ? float prePreviousPointY = Float.NaN;
? ? ? ? float previousPointX = Float.NaN;
? ? ? ? float previousPointY = Float.NaN;
? ? ? ? float currentPointX = Float.NaN;
? ? ? ? float currentPointY = Float.NaN;
? ? ? ? float nextPointX;
? ? ? ? float nextPointY;
? ? ? ? int lineSize = mXData.size();
? ? ? ? for (int i = 0; i < lineSize; i++) {
? ? ? ? ? ? float x;
? ? ? ? ? ? float y;
? ? ? ? ? ? if (Float.isNaN(currentPointX)) {
? ? ? ? ? ? ? ? currentPointX = getSpinnerPoint(i).x;
? ? ? ? ? ? ? ? currentPointY = getSpinnerPoint(i).y;
? ? ? ? ? ? }
? ? ? ? ? ? if (Float.isNaN(previousPointX)) {
? ? ? ? ? ? ? ? //是第一個點?
? ? ? ? ? ? ? ? if (i > 0) {
? ? ? ? ? ? ? ? ? ? previousPointX = getSpinnerPoint(i - 1).x;
? ? ? ? ? ? ? ? ? ? previousPointY = getSpinnerPoint(i - 1).y;
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? //用當(dāng)前點表示上一個點
? ? ? ? ? ? ? ? ? ? previousPointX = currentPointX;
? ? ? ? ? ? ? ? ? ? previousPointY = currentPointY;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }

? ? ? ? ? ? if (Float.isNaN(prePreviousPointX)) {
? ? ? ? ? ? ? ? //是前兩個點?
? ? ? ? ? ? ? ? if (i > 1) {
? ? ? ? ? ? ? ? ? ? prePreviousPointX = getSpinnerPoint(i - 2).x;
? ? ? ? ? ? ? ? ? ? prePreviousPointY = getSpinnerPoint(i - 2).y;
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? //當(dāng)前點表示上上個點
? ? ? ? ? ? ? ? ? ? prePreviousPointX = previousPointX;
? ? ? ? ? ? ? ? ? ? prePreviousPointY = previousPointY;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }

? ? ? ? ? ? // 判斷是不是最后一個點了
? ? ? ? ? ? if (i < lineSize - 1) {
? ? ? ? ? ? ? ? nextPointX = getSpinnerPoint(i + 1).x;
? ? ? ? ? ? ? ? nextPointY = getSpinnerPoint(i + 1).y;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? //用當(dāng)前點表示下一個點
? ? ? ? ? ? ? ? nextPointX = currentPointX;
? ? ? ? ? ? ? ? nextPointY = currentPointY;
? ? ? ? ? ? }

? ? ? ? ? ? if (i == 0) {
? ? ? ? ? ? ? ? // 將Path移動到開始點
? ? ? ? ? ? ? ? path.moveTo(currentPointX, currentPointY);
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? // 求出控制點坐標(biāo)
? ? ? ? ? ? ? ? final float firstDiffX = (currentPointX - prePreviousPointX);
? ? ? ? ? ? ? ? final float firstDiffY = (currentPointY - prePreviousPointY);
? ? ? ? ? ? ? ? final float secondDiffX = (nextPointX - previousPointX);
? ? ? ? ? ? ? ? final float secondDiffY = (nextPointY - previousPointY);
? ? ? ? ? ? ? ? final float firstControlPointX = previousPointX + (mLineSmoothness * firstDiffX);
? ? ? ? ? ? ? ? final float firstControlPointY = previousPointY + (mLineSmoothness * firstDiffY);
? ? ? ? ? ? ? ? final float secondControlPointX = currentPointX - (mLineSmoothness * secondDiffX);
? ? ? ? ? ? ? ? final float secondControlPointY = currentPointY - (mLineSmoothness * secondDiffY);
? ? ? ? ? ? ? ? //畫出曲線
? ? ? ? ? ? ? ? path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,
? ? ? ? ? ? ? ? ? ? ? ? currentPointX, currentPointY);
? ? ? ? ? ? }

? ? ? ? ? ? // 更新
? ? ? ? ? ? prePreviousPointX = previousPointX;
? ? ? ? ? ? prePreviousPointY = previousPointY;
? ? ? ? ? ? previousPointX = currentPointX;
? ? ? ? ? ? previousPointY = currentPointY;
? ? ? ? ? ? currentPointX = nextPointX;
? ? ? ? ? ? currentPointY = nextPointY;
? ? ? ? }
? ? ? ? canvas.drawPath(path, mSpinnerLinePaint);
? ? }

? ? /**
? ? ?* 繪制XY坐標(biāo)
? ? ?*/
? ? private void drawXY(Canvas canvas) {
? ? ? ? int length = dpToPx(5);//刻度的長度
? ? ? ? //繪制Y坐標(biāo)
? ? ? ? canvas.drawLine(mXOri - xyLineWidth / 2, 0, mXOri - xyLineWidth / 2, mYOri, mXYPaint);
? ? ? ? //繪制箭頭
? ? ? ? mXYPaint.setStyle(Paint.Style.STROKE);
? ? ? ? Path path = new Path();
? ? ? ? path.moveTo(mXOri - xyLineWidth / 2 - dpToPx(5), dpToPx(12));
? ? ? ? path.lineTo(mXOri - xyLineWidth / 2, xyLineWidth / 2);
? ? ? ? path.lineTo(mXOri - xyLineWidth / 2 + dpToPx(5), dpToPx(12));
? ? ? ? canvas.drawPath(path, mXYPaint);
? ? ? ? //繪制刻度
? ? ? ? int yLength = (int) (mYOri * (1 - 0.1f) / (mYData.size() - 1));//y軸上面空出10%,計算出y軸刻度間距
? ? ? ? for (int i = 0; i < mYData.size(); i++) {
? ? ? ? ? ? //繪制刻度
? ? ? ? ? ? canvas.drawLine(mXOri, mYOri - yLength * i + xyLineWidth / 2, mXOri + length, mYOri - yLength * i + xyLineWidth / 2, mXYPaint);
? ? ? ? ? ? mXYTextPaint.setColor(xyTextColor);
? ? ? ? ? ? //繪制文本
? ? ? ? ? ? String text = mYData.get(i) + "";
? ? ? ? ? ? Rect rect = getTextBounds(text, mXYTextPaint);
? ? ? ? ? ? canvas.drawText(text, 0, text.length(), mXOri - xyLineWidth - dpToPx(2) - rect.width(), mYOri - yLength * i + rect.height() / 2, mXYTextPaint);
? ? ? ? }
? ? ? ? //繪制坐標(biāo)
? ? ? ? canvas.drawLine(mXOri, mYOri + xyLineWidth / 2, width, mYOri + xyLineWidth / 2, mXYPaint);
? ? ? ? //繪制箭頭
? ? ? ? mXYPaint.setStyle(Paint.Style.STROKE);
? ? ? ? path = new Path();
? ? ? ? //整個長度
? ? ? ? float xLength = mXInit + interval * (mXData.size() - 1) + (width - mXOri) * 0.1f;
? ? ? ? if (xLength < width)
? ? ? ? ? ? xLength = width;
? ? ? ? path.moveTo(xLength - dpToPx(12), mYOri + xyLineWidth / 2 - dpToPx(5));
? ? ? ? path.lineTo(xLength - xyLineWidth / 2, mYOri + xyLineWidth / 2);
? ? ? ? path.lineTo(xLength - dpToPx(12), mYOri + xyLineWidth / 2 + dpToPx(5));
? ? ? ? canvas.drawPath(path, mXYPaint);
? ? ? ? //繪制x軸刻度
? ? ? ? for (int i = 0; i < mXData.size(); i++) {
? ? ? ? ? ? float x = mXInit + interval * i;
? ? ? ? ? ? if (x >= mXOri) {//只繪制從原點開始的區(qū)域
? ? ? ? ? ? ? ? mXYTextPaint.setColor(xyTextColor);
? ? ? ? ? ? ? ? canvas.drawLine(x, mYOri, x, mYOri - length, mXYPaint);
? ? ? ? ? ? ? ? //繪制X軸文本
? ? ? ? ? ? ? ? String text = mXData.get(i);
? ? ? ? ? ? ? ? Rect rect = getTextBounds(text, mXYTextPaint);
? ? ? ? ? ? ? ? if (i == selectIndex - 1) {
? ? ? ? ? ? ? ? ? ? mXYTextPaint.setColor(lineColor);
? ? ? ? ? ? ? ? ? ? canvas.drawText(text, 0, text.length(), x - rect.width() / 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint);
? ? ? ? ? ? ? ? ? ? canvas.drawRoundRect(x - xValueRect.width() / 2 - dpToPx(3), mYOri + xyLineWidth + dpToPx(1), x + xValueRect.width() / 2 + dpToPx(3), mYOri + xyLineWidth + dpToPx(2) + xValueRect.height() + dpToPx(2), dpToPx(2), dpToPx(2), mXYTextPaint);
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? canvas.drawText(text, 0, text.length(), x - rect.width() / 2, mYOri + xyLineWidth + dpToPx(2) + rect.height(), mXYTextPaint);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }

? ? private float startX;
? ? private float startx;

? ? @Override
? ? public boolean onTouchEvent(MotionEvent event) {
? ? ? ? if (isScrolling)
? ? ? ? ? ? return super.onTouchEvent(event);
? ? ? ? ? ? //當(dāng)該view獲得點擊事件,就請求父控件不攔截事件
? ? ? ? this.getParent().requestDisallowInterceptTouchEvent(true);
? ? ? ? obtainVelocityTracker(event);
? ? ? ? switch (event.getAction()) {
? ? ? ? ? ? case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? startX = event.getX();
? ? ? ? ? ? ? ? startx = event.getX();
? ? ? ? ? ? ? ? Log.e("XXXX", "down:" + startX + "");
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? //滑動距離小于等于8的時候任務(wù)為短距離滑動
? ? ? ? ? ? ? ? //當(dāng)前x軸的尺寸與設(shè)置的x軸間隔的距離之乘積大于 屏幕中的顯示布局寬度與x軸七點之差時,開始移動
? ? ? ? ? ? ? ? if (interval * mXData.size() > width - mXOri) {
? ? ? ? ? ? ? ? ? ? //獲取滑動的距離
? ? ? ? ? ? ? ? ? ? float dis = event.getX() - startX;
? ? ? ? ? ? ? ? ? ? //重新賦值給startX
? ? ? ? ? ? ? ? ? ? startX = event.getX();
? ? ? ? ? ? ? ? ? ? //當(dāng)前x原點距離與左右滑動的距離之和沒有最小值大,則將當(dāng)前x距離賦值為最小,以下相似
? ? ? ? ? ? ? ? ? ? if (mXInit + dis < minXInit) {
? ? ? ? ? ? ? ? ? ? ? ? mXInit = minXInit;
? ? ? ? ? ? ? ? ? ? } else if (mXInit + dis > maxXInit) {
? ? ? ? ? ? ? ? ? ? ? ? mXInit = maxXInit;
? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? mXInit = mXInit + dis;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? invalidate();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? isShortSlide = Math.abs(event.getX() - startx) <= dpToPx(8);
? ? ? ? ? ? ? ? clickAction(event);
? ? ? ? ? ? ? ? scrollAfterActionUp();
? ? ? ? ? ? ? ? this.getParent().requestDisallowInterceptTouchEvent(false);
? ? ? ? ? ? ? ? recycleVelocityTracker();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_CANCEL:
? ? ? ? ? ? ? ? //增加這行代碼防止與父類的滑動事件沖突
? ? ? ? ? ? ? ? this.getParent().requestDisallowInterceptTouchEvent(false);
? ? ? ? ? ? ? ? recycleVelocityTracker();
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? return true;
? ? }

? ? //是否正在滑動
? ? private boolean isScrolling = false;

? ? /**
? ? ?* 手指抬起后的滑動處理
? ? ?*/
? ? private void scrollAfterActionUp() {
? ? ? ? if (!isScroll)
? ? ? ? ? ? return;
? ? ? ? final float velocity = getVelocity();
? ? ? ? float scrollLength = maxXInit - minXInit;
? ? ? ? if (Math.abs(velocity) < 10000)
? ? ? ? ? ? scrollLength = (maxXInit - minXInit) * Math.abs(velocity) / 10000;
? ? ? ? ValueAnimator animator = ValueAnimator.ofFloat(0, scrollLength);
? ? ? ? animator.setDuration((long) (scrollLength / (maxXInit - minXInit) * 1000));//時間最大為1000毫秒,此處使用比例進行換算
? ? ? ? animator.setInterpolator(new DecelerateInterpolator());
? ? ? ? animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationUpdate(ValueAnimator valueAnimator) {
? ? ? ? ? ? ? ? float value = (float) valueAnimator.getAnimatedValue();
? ? ? ? ? ? ? ? if (velocity < 0 && mXInit > minXInit) {//向左滑動
? ? ? ? ? ? ? ? ? ? if (mXInit - value <= minXInit)
? ? ? ? ? ? ? ? ? ? ? ? mXInit = minXInit;
? ? ? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? ? ? mXInit = mXInit - value;
? ? ? ? ? ? ? ? } else if (velocity > 0 && mXInit < maxXInit) {//向右滑動
? ? ? ? ? ? ? ? ? ? if (mXInit + value >= maxXInit)
? ? ? ? ? ? ? ? ? ? ? ? mXInit = maxXInit;
? ? ? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? ? ? mXInit = mXInit + value;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? invalidate();
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? animator.addListener(new Animator.AnimatorListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationStart(Animator animator) {
? ? ? ? ? ? ? ? isScrolling = true;
? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationEnd(Animator animator) {
? ? ? ? ? ? ? ? isScrolling = false;
? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationCancel(Animator animator) {
? ? ? ? ? ? ? ? isScrolling = false;
? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationRepeat(Animator animator) {

? ? ? ? ? ? }
? ? ? ? });
? ? ? ? animator.start();

? ? }

? ? /**
? ? ?* 獲取速度
? ? ?*
? ? ?* @return
? ? ?*/
? ? private float getVelocity() {
? ? ? ? if (mTracker != null) {
? ? ? ? ? ? mTracker.computeCurrentVelocity(1000);
? ? ? ? ? ? return mTracker.getXVelocity();
? ? ? ? }
? ? ? ? return 0;
? ? }

? ? /**
? ? ?* 點擊X軸坐標(biāo)或者折線節(jié)點
? ? ?* ?*/
? ? // 44 ?142 ?139
? ? private void clickAction(MotionEvent event) {
? ? ? ? int dp8 = dpToPx(8);
? ? ? ? float eventX = event.getX();
? ? ? ? float eventY = event.getY();
? ? ? ? if (!isShortSlide) {
? ? ? ? ? ? for (int i = 0; i < mXData.size(); i++) {
? ? ? ? ? ? ? ? float x = mXInit + interval * i;
? ? ? ? ? ? ? ? float start = mXOri;
? ? ? ? ? ? ? ? if (x >= start + (mSelectMiddle - 1) * interval && x < start + mSelectMiddle * interval) {
? ? ? ? ? ? ? ? ? ? selectIndex = i + 1;
? ? ? ? ? ? ? ? ? ? invalidate();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? for (int i = 0; i < mXData.size(); i++) {
? ? ? ? ? ? //節(jié)點
? ? ? ? ? ? float x = mXInit + interval * i;
? ? ? ? ? ? float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(i)) / mYData.get(mYData.size() - 1);
? ? ? ? ? ? if (eventX >= x - dp8 && eventX <= x + dp8 &&
? ? ? ? ? ? ? ? ? ? eventY >= y - dp8 && eventY <= y + dp8 && selectIndex != i + 1) {//每個節(jié)點周圍范圍內(nèi)都是可點擊區(qū)域
? ? ? ? ? ? ? ? selectIndex = i + 1;
? ? ? ? ? ? ? ? invalidate();
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? ? ? //X軸刻度
? ? ? ? ? ? String text = mXData.get(i);
? ? ? ? ? ? Rect rect = getTextBounds(text, mXYTextPaint);
? ? ? ? ? ? x = mXInit + interval * i;
? ? ? ? ? ? y = mYOri + xyLineWidth + dpToPx(2);
? ? ? ? ? ? if (eventX >= x - rect.width() / 2 - dp8 && eventX <= x + rect.width() + dp8 / 2 &&
? ? ? ? ? ? ? ? ? ? eventY >= y - dp8 && eventY <= y + rect.height() + dp8 && selectIndex != i + 1) {
? ? ? ? ? ? ? ? selectIndex = i + 1;
? ? ? ? ? ? ? ? invalidate();
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? }
? ? }


? ? /**
? ? ?* 獲取速度跟蹤器
? ? ?*
? ? ?* @param event
? ? ?*/
? ? private void obtainVelocityTracker(MotionEvent event) {
? ? ? ? if (!isScroll)
? ? ? ? ? ? return;
? ? ? ? if (mTracker == null) {
? ? ? ? ? ? mTracker = VelocityTracker.obtain();
? ? ? ? }
? ? ? ? mTracker.addMovement(event);
? ? }

? ? /**
? ? ?* 回收速度跟蹤器
? ? ?*/
? ? private void recycleVelocityTracker() {
? ? ? ? if (mTracker != null) {
? ? ? ? ? ? mTracker.recycle();
? ? ? ? ? ? mTracker = null;
? ? ? ? }
? ? }

? ? /**
? ? ?* 根據(jù)用戶輸入顯示類型,在滑動時在不同的位置顯示提示框
? ? ?*/
? ? private int getSelectIndexFromShowType(int showPositionType) {
? ? ? ? int visibleScale = (width - mXOri) / interval;
? ? ? ? switch (showPositionType) {
? ? ? ? ? ? case FIRST:
? ? ? ? ? ? ? ? mSelectMiddle = 1;
? ? ? ? ? ? ? ? return mSelectMiddle;
? ? ? ? ? ? case MIDDLE:
? ? ? ? ? ? ? ? if (mXData.size() <= visibleScale) {
? ? ? ? ? ? ? ? ? ? mSelectMiddle = middleIndex(mXData.size());
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? mSelectMiddle = middleIndex(visibleScale);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return mSelectMiddle; ?//屏幕可顯示的刻度
? ? ? ? ? ? case END:
? ? ? ? ? ? ? ? if (mXData.size() <= visibleScale) {
? ? ? ? ? ? ? ? ? ? mSelectMiddle = mXData.size();
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? mSelectMiddle = visibleScale;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return visibleScale;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? mSelectMiddle = 0;
? ? ? ? ? ? ? ? return mSelectMiddle;
? ? ? ? }
? ? }

? ? public void setValue(Map<String, Integer> value) {
? ? ? ? this.mSpinnerValue = value;
? ? ? ? invalidate();
? ? }

? ? public void setValue(Map<String, Integer> value, List<String> xValue, List<Integer> yValue) {
? ? ? ? this.mSpinnerValue = value;
? ? ? ? this.mXData = xValue;
? ? ? ? this.mYData = yValue;
? ? ? ? invalidate();
? ? }


? ? public Map<String, Integer> getValue() {
? ? ? ? return mSpinnerValue;
? ? }

? ? /**
? ? ?* 獲取丈量文本的矩形
? ? ?*
? ? ?* @param text
? ? ?* @param paint
? ? ?* @return
? ? ?*/
? ? private Rect getTextBounds(String text, Paint paint) {
? ? ? ? Rect rect = new Rect();
? ? ? ? paint.getTextBounds(text, 0, text.length(), rect);
? ? ? ? return rect;
? ? }

? ? /**
? ? ?* dp轉(zhuǎn)化成為px
? ? ?*
? ? ?* @param dp
? ? ?* @return
? ? ?*/
? ? private int dpToPx(int dp) {
? ? ? ? float density = getContext().getResources().getDisplayMetrics().density;
? ? ? ? return (int) (dp * density + 0.5f * (dp >= 0 ? 1 : -1));
? ? }

? ? /**
? ? ?* sp轉(zhuǎn)化為px
? ? ?*
? ? ?* @param sp
? ? ?* @return
? ? ?*/
? ? private int spToPx(int sp) {
? ? ? ? float scaledDensity = getContext().getResources().getDisplayMetrics().scaledDensity;
? ? ? ? return (int) (scaledDensity * sp + 0.5f * (sp >= 0 ? 1 : -1));
? ? }

? ? /**
? ? ?* 獲取集合中最長的index
? ? ?*/
? ? private static final int NULL_INDEX = -1;

? ? public int getListItemMaxIndex(List<?> data) {
? ? ? ? if (data == null || data.size() < 1) {
? ? ? ? ? ? return NULL_INDEX;
? ? ? ? }
? ? ? ? int max = (data.get(0) + "").length();
? ? ? ? for (int i = 0; i < data.size(); i++) {
? ? ? ? ? ? String s = data.get(i) + "";
? ? ? ? ? ? if (s.length() > max) {
? ? ? ? ? ? ? ? return i;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return NULL_INDEX;
? ? }

? ? //獲得在滑動結(jié)束的時候在屏幕內(nèi)的點
? ? private int middleIndex(int size) {
? ? ? ? if (size % 2 == 0) {
? ? ? ? ? ? return size / 2;
? ? ? ? } else {
? ? ? ? ? ? return size / 2 + 1;
? ? ? ? }
? ? }


? ? /**
? ? ?* 根據(jù)兩點坐標(biāo)獲取中間某個點
? ? ?*
? ? ?* @param from 坐標(biāo)1
? ? ?* @param to ? 坐標(biāo)2
? ? ?*/

? ? //獲取已知點的斜率 y = kx+b
? ? private float getSlope(Point from, Point to) {
? ? ? ? float k = (to.y - from.y) / (to.x - from.x);
? ? ? ? Log.e("Point", "參數(shù)b:" + k);
? ? ? ? return k;
? ? }

? ? //獲取參數(shù) b
? ? private float getParams(Point from, Point to) {
? ? ? ? float b = from.y - (getSlope(from, to) * from.x);
? ? ? ? Log.e("Point", "參數(shù)b:" + b);
? ? ? ? return b;
? ? }

? ? //根據(jù)兩點間的坐標(biāo)獲取x軸的任意一個坐標(biāo)x值,
? ? private float getArbitrarilyX(Point from, Point to, int grade, int needGrade) {
? ? ? ? //獲得輸入的新坐標(biāo)
? ? ? ? float x = ((to.x - from.x) * needGrade) / grade + from.x;
? ? ? ? Log.e("Point", "x坐標(biāo)值:" + x);
? ? ? ? return x;
? ? }

? ? //獲取坐標(biāo)值
? ? private Point getPoint(Point from, Point to, int grade, int needGrade) {
? ? ? ? Point point = new Point();
? ? ? ? point.setX(getArbitrarilyX(from, to, grade, needGrade));
? ? ? ? float slope = getSlope(from, to);
? ? ? ? point.setY(slope * point.x + getParams(from, to));
? ? ? ? return point;
? ? }

? ? //獲取繪制折線的點
? ? private Point getSpinnerPoint(int valueIndex) {
? ? ? ? float x = mXInit + interval * (valueIndex);
? ? ? ? float y = mYOri - mYOri * (1 - 0.1f) * mSpinnerValue.get(mXData.get(valueIndex)) / mYData.get(mYData.size() - 1);
? ? ? ? return new Point(x, y);
? ? }

? ? private class Point {
? ? ? ? float x;
? ? ? ? float y;

? ? ? ? public Point() {
? ? ? ? }

? ? ? ? public float getX() {
? ? ? ? ? ? return x;
? ? ? ? }

? ? ? ? public void setX(float x) {
? ? ? ? ? ? this.x = x;
? ? ? ? }

? ? ? ? public float getY() {
? ? ? ? ? ? return y;
? ? ? ? }

? ? ? ? public void setY(float y) {
? ? ? ? ? ? this.y = y;
? ? ? ? }

? ? ? ? public Point(float x, float y) {
? ? ? ? ? ? this.x = x;
? ? ? ? ? ? this.y = y;
? ? ? ? }

? ? ? ? @Override
? ? ? ? public String toString() {
? ? ? ? ? ? return "Point{" +
? ? ? ? ? ? ? ? ? ? "x=" + x +
? ? ? ? ? ? ? ? ? ? ", y=" + y +
? ? ? ? ? ? ? ? ? ? '}';
? ? ? ? }
? ? }
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android ellipsize的小問題介紹

    Android ellipsize的小問題介紹

    使用TextView的時候,需要長度過長自動顯示省略號,android里有原生的支持,本文將針對此問題進行深入剖析,需要的朋友可以參考
    2012-11-11
  • Android開發(fā)中Activity的生命周期及加載模式詳解

    Android開發(fā)中Activity的生命周期及加載模式詳解

    這篇文章主要介紹了Android開發(fā)中Activity的生命周期及加載模式詳解的相關(guān)資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下
    2016-05-05
  • Android適配器(Adapter)的概念與自定義

    Android適配器(Adapter)的概念與自定義

    這篇文章主要給大家介紹了關(guān)于Android適配器(Adapter)的相關(guān)資料,適配器是一個非常重要的知識點,Adapter是用來幫助填出數(shù)據(jù)的中間橋梁,本文介紹的非常詳細,需要的朋友可以參考下
    2021-07-07
  • android textview 顯示html方法解析

    android textview 顯示html方法解析

    現(xiàn)在網(wǎng)絡(luò)的繁盛時代,光文字是不能滿足人們的胃口的,圖片,flash,音頻,視頻就成為瀏覽網(wǎng)頁的主流顯示,在手機上也一樣,本文將詳細介紹此功能的實現(xiàn)方法
    2012-11-11
  • Android 事件觸發(fā)機制的深入學(xué)習(xí)

    Android 事件觸發(fā)機制的深入學(xué)習(xí)

    這篇文章主要介紹了 Android 事件觸發(fā)機制的深入學(xué)習(xí)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Android系統(tǒng)檢測程序內(nèi)存占用各種方法

    Android系統(tǒng)檢測程序內(nèi)存占用各種方法

    這篇文章主要介紹了Android系統(tǒng)檢測程序內(nèi)存占用各種方法,本文講解了檢查系統(tǒng)總內(nèi)存、檢查某個程序的各類型內(nèi)存占用、檢查程序狀態(tài)、檢查程序各部分的內(nèi)存占用等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • Android組件之間交互核心Intent用法分析

    Android組件之間交互核心Intent用法分析

    這篇文章主要介紹了Android組件之間交互核心Intent用法,結(jié)合實例形式分析了Intent實現(xiàn)組件之間交互的步驟與相關(guān)技巧,需要的朋友可以參考下
    2016-06-06
  • Flutter實現(xiàn)編寫富文本Text的示例代碼

    Flutter實現(xiàn)編寫富文本Text的示例代碼

    這篇文章主要為大家詳細介紹了如何通過Flutter實現(xiàn)編寫富文本Text,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以參考一下
    2022-11-11
  • 簡單談?wù)刟ndroid studio 的單元測試

    簡單談?wù)刟ndroid studio 的單元測試

    昨天在完善項目的時候,需要進行單元測試,在Eclipse環(huán)境中進行是很簡單的,但是在Android Studio環(huán)境中進行單元測試,在國內(nèi)找了很多資料,大都是人云亦云,本文發(fā)布出來供大家學(xué)習(xí)參考。
    2016-08-08
  • Android仿Win8的metro的UI界面(上)

    Android仿Win8的metro的UI界面(上)

    這篇文章主要為大家詳細介紹了Android仿Win8的metro的UI界面,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08

最新評論