之前在项目是哪个用到了渐进色曲线,搜索了贝塞尔曲线的实现原理,仔细读了这篇文章后,弄懂了实现原理自己实现了一份。https://blog.csdn.net/devallever/article/details/78352928点击打开链接:Android-自定义贝塞尔曲线图表控件

上效果图 :仅做7天数据展示,mark仅简单做了下。实现原理我参考的这篇文章:点击打开链接

当然x轴和Y轴的刻度线都画好了,目前在代码里控制

全部代码:

package com.example.widget.chart;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.lanchuang.oiip.R;
import com.lanchuang.oiip.utils.DensityUtil;
import com.lanchuang.oiip.utils.DensityUtils;

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

/**
 * @author: sunzhibin
 * <p>
 * date: 2018/5/12.
 * description: 渐进色贝塞尔曲线
 * e-mail: E-mail
 * modify: the history
 * </p>
 */
public class LineChartView extends View {private final static String TAG = "LineChartView";
    //画 X/Y轴
    private Paint mXLineTextPaint;
    //    画 Y轴
//    private Paint mYLinePaint;
    private Paint mBezierPaint;
    private Paint mXPaint;
    private Paint mYPaint;
    private Paint mCirclePaint;
    private Paint mMarkPaint;
    private float mMarginLeftRight;
    private int mMarginTopBottom = 10;

    //控件宽高
    private float mWidth;
    private int mHeight;

    private List<String> mXNameList;
    private List<LineDataSet> mLineDataSetList;
    private List<List<BezierLineData>> mBezierLineDataList;
    private List<PointF> mOriginDataList;
    private List<PointF> mNewDataList;//转变Android坐标后的数据
    private float mDownX;
    //
    private List<PointF> xvalPointF;//X轴每个刻度的坐标
    private PointF mMaxYPointF;//Y轴方向最大值坐标点
    private PointF mMinYPointF;
    private float mMaxYValue;//真实数据的最大值
    private float mMinYValue;
    private boolean isChoocePoint = false;
    private boolean isNeedPoint = false;
    //选中点
    float cx = -1;
    float cy = -1;
    //marker框的大小
    private float mMarkHeight = DensityUtil.dip2px(getContext(), 20);
    private float mMarkWidth = DensityUtil.dip2px(getContext(), 20);
    private int mMarkColor = 0xFFCB05FF;
    private int mPosition = -1;
    private int[] mGradientColors = new int[]{getResources().getColor(R.color.color_gradient_origin),
            getResources().getColor(R.color.color_gradient_origin2),
            getResources().getColor(R.color.color_gradient_origin)};

    private int mMarkTextSize = 12;
    private int mYTextSize = 12;
    private int mXTextSize = 12;
    private int mYTextColor = getResources().getColor(R.color.color_text_gray_hint);
    private int mXTextColor = getResources().getColor(R.color.color_text_gray_hint);
    private int mLineTextColor = 0x66cccccc;
    private int mXLineTextColor = 0x66cccccc;
    private int mBezierLineWidth = 3;
    private int mBgLineWidth = 2;
    private String mCurrentData = "";
    // y轴字距离Y轴的距离
    private float textYpaddingY = DensityUtil.dip2px(getContext(), 5);
    //x轴字距离x轴距离
    private float textXpaddingX = DensityUtil.dip2px(getContext(), 0);
    private float textXBottomX = DensityUtil.dip2px(getContext(), 10f);
    //是否需要画刻度线
    private boolean isNeedYRuling = false;
    private boolean isNeedXRuling = false;

    public LineChartView(Context context) {super(context);
        initAtrrs(context, null);
        init();
    }public LineChartView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);
        initAtrrs(context, attrs);
        init();
    }public LineChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
        initAtrrs(context, attrs);
        init();
    }@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public LineChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);
        initAtrrs(context, attrs);
        init();
    }private void initAtrrs(Context context, AttributeSet attrs) {final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.LineChartView);
        mMaxYValue = (int) a.getDimension(R.styleable.LineChartView_maxvalue, mMaxYValue);
        mMinYValue = (int) a.getDimension(R.styleable.LineChartView_minvalue, mMinYValue);
        mMarkHeight = (int) a.getDimension(R.styleable.LineChartView_markHeight, DensityUtils.dip2px(context, mMarkHeight));
        mBezierLineWidth = (int) a.getDimension(R.styleable.LineChartView_bezier_line_width, DensityUtils.dip2px(context, mBezierLineWidth));
        mBgLineWidth = (int) a.getDimension(R.styleable.LineChartView_bg_line_width, DensityUtils.dip2px(context, mBgLineWidth));

        mMarkWidth = (int) a.getDimension(R.styleable.LineChartView_markWidth, DensityUtils.dip2px(context, mMarkWidth));
        mMarkTextSize = (int) a.getDimension(R.styleable.LineChartView_markTextSize, DensityUtils.dip2px(context, mMarkTextSize));
        mXTextSize = (int) a.getDimension(R.styleable.LineChartView_xTextSize, DensityUtils.dip2px(context, mXTextSize));
        mYTextSize = (int) a.getDimension(R.styleable.LineChartView_yTextSize, DensityUtils.dip2px(context, mYTextSize));

        mYTextColor = a.getColor(R.styleable.LineChartView_yTextColor, mYTextColor);
        mXTextColor = a.getColor(R.styleable.LineChartView_xTextColor, mXTextColor);
        mLineTextColor = a.getColor(R.styleable.LineChartView_lineTextColor, mLineTextColor);
        mXLineTextColor = a.getColor(R.styleable.LineChartView_xLineTextColor, mXLineTextColor);
        a.recycle();

    }private void init() {mXLineTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBezierPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mXPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mMarkPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mYPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        mXLineTextPaint.setDither(true);
        mBezierPaint.setDither(true);
        mXPaint.setDither(true);
        mCirclePaint.setDither(true);
        mMarkPaint.setDither(true);
        mYPaint.setDither(true);

        mXLineTextPaint.setAntiAlias(true);
        mBezierPaint.setAntiAlias(true);
        mXPaint.setAntiAlias(true);
        mCirclePaint.setAntiAlias(true);
        mMarkPaint.setAntiAlias(true);
        mYPaint.setAntiAlias(true);

        mBezierPaint.setStyle(Paint.Style.STROKE);
        mBezierPaint.setStrokeWidth(mBezierLineWidth);//设置线宽
        mBezierPaint.setAntiAlias(true);//去除锯齿
        mBezierPaint.setStrokeJoin(Paint.Join.ROUND);
        mBezierPaint.setStrokeCap(Paint.Cap.ROUND);

        mMarkPaint.setStyle(Paint.Style.FILL);
        mMarkPaint.setTextSize(mMarkTextSize);
        mMarkPaint.setColor(mMarkColor);

        mXPaint.setTextSize(mXTextSize);
        mYPaint.setTextSize(mYTextSize);

        mYPaint.setColor(mYTextColor);
        mXPaint.setColor(mXTextColor);
        mXLineTextPaint.setColor(mXLineTextColor);

        mXNameList = new ArrayList<>();
        mLineDataSetList = new ArrayList<>();
        mBezierLineDataList = new ArrayList<>();
        mOriginDataList = new ArrayList<>();
        xvalPointF = new ArrayList<>();
        mNewDataList = new ArrayList<>();

        mMaxYPointF = new PointF();
        mMinYPointF = new PointF();

        //设置X轴数据
        for (int i = 0; i < 7; i++) {mXNameList.add("12/0" + i);
        }setxDataList(mXNameList);
        //设置Y轴数据
        mOriginDataList.add(new PointF(1, 300));
        mOriginDataList.add(new PointF(2, 500));
        mOriginDataList.add(new PointF(3, 300));
        mOriginDataList.add(new PointF(4, 500));
        mOriginDataList.add(new PointF(5, 300));
        mOriginDataList.add(new PointF(6, 500));
        mOriginDataList.add(new PointF(7, 400));
        setYDataList(mOriginDataList);

    }@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        if (mMarginTopBottom == 0)mMarginTopBottom = getPaddingBottom();
        if (mMarginLeftRight == 0)mMarginLeftRight = getPaddingLeft();
    }@Override
    protected void onDraw(Canvas canvas) {super.onDraw(canvas);
        drawHorizonLine(canvas);
        drawXLable(canvas);
        drawBezier(canvas);
        drawMark(canvas);
    }/**
     * 画5条分割线
     */
    private void drawHorizonLine(Canvas canvas) {float intervalY = (getMeasuredHeight() - mMarginTopBottom * 2) / 4;//每条线段的间隔
        float textHeight = DensityUtils.getFontHeight(mXPaint);
        float textWidth = mYPaint.measureText(mMaxYValue + "");
        float textHeight2 = DensityUtils.getFontHeight(mYPaint);
        if (mMarginLeftRight < textWidth) {mMarginLeftRight = textWidth + textYpaddingY;
        }
//        mYPaint.setStrokeWidth(mBgLineWidth);
//        mYPaint.setColor(0x66cccccc);
        for (int i = 0; i < 5; i++) {//绘制X轴
            if (i == 0) {canvas.drawLine(mMarginLeftRight - textYpaddingY/2,
                        mHeight - textHeight - textXpaddingX - textXBottomX - intervalY * i,
                        mWidth,
                        mHeight - textHeight - textXpaddingX - textXBottomX - intervalY * i,
                        mXLineTextPaint);
            } else if (isNeedXRuling) {//绘制Y轴上x方向的刻度线
                canvas.drawLine(mMarginLeftRight + textYpaddingY,
                        mHeight - textHeight - textXpaddingX - textXBottomX - intervalY * i,
                        mWidth,
                        mHeight - textHeight - textXpaddingX - textXBottomX - intervalY * i,
                        mXLineTextPaint);
            }if (i == 0) {float tempWidth = mYPaint.measureText(mMaxYValue + "");
                textWidth = mYPaint.measureText(i * (mMaxYValue - mMinYValue) + "");
                textWidth += tempWidth / 2f - textWidth / 2f;
            } else {textWidth = mYPaint.measureText(i * (mMaxYValue - mMinYValue) + "");
            }canvas.drawText(i * (mMaxYValue - mMinYValue) + "", mMarginLeftRight - textWidth,
                    mHeight - textHeight - textXBottomX - textXpaddingX - intervalY * i + textHeight2 / 4
                    , mYPaint);
        }mMinYPointF = new PointF(mMarginLeftRight,
                mHeight - textHeight - DensityUtil.dip2px(getContext(), 5f) - mMarginTopBottom);
        mMaxYPointF = new PointF(mMarginLeftRight, mMarginTopBottom);
        changePoint(mOriginDataList);

    }/**
     * 画横坐标、Y轴
     */
    private void drawXLable(Canvas canvas) {xvalPointF.clear();
        float textWidth = mXPaint.measureText(mXNameList.get(0));
        float textHeight = DensityUtils.getFontHeight(mXPaint);
//        if (mMarginLeftRight == 0 || mMarginLeftRight < textWidth / 2f) {
//            mMarginLeftRight = textWidth / 2;
//        }
        float xNameintervalX = (mWidth - mMarginLeftRight - textWidth - textYpaddingY) / (mXNameList.size() - 1);//横坐标的间隔
        for (int i = 0; i < mXNameList.size(); i++) {canvas.drawText(mXNameList.get(i),
                    mMarginLeftRight + xNameintervalX * i + textYpaddingY,
                    mHeight - textXBottomX,
                    mXPaint);
            //绘制Y轴
            if (i == 0) {canvas.drawLine(mMarginLeftRight + xNameintervalX * i + textYpaddingY,
                        mHeight - textHeight - textXpaddingX - textXBottomX,
                        mMarginLeftRight + xNameintervalX * i + textYpaddingY,
                        0 + mMarginTopBottom,
                        mXLineTextPaint);
            }//绘制x轴上的Y方向的刻度线
            if (isNeedYRuling) {canvas.drawLine(mMarginLeftRight + xNameintervalX * i + textYpaddingY + textWidth / 2,
                        mHeight - textHeight - textXpaddingX - textXBottomX,
                        mMarginLeftRight + xNameintervalX * i + textYpaddingY + textWidth / 2,
                        0 + mMarginTopBottom,
                        mXLineTextPaint);
            }xvalPointF.add(new PointF(mMarginLeftRight + xNameintervalX * i + textYpaddingY + textWidth / 2,
                    mHeight - textHeight - textXpaddingX - textXBottomX));
        }}private void drawBezier(Canvas canvas) {for (int i = 0; i < mLineDataSetList.size(); i++) {LineDataSet lineDataSet = mLineDataSetList.get(i);
            mBezierLineDataList.add(bezierLineData(changePoint(i, lineDataSet.getOldPointFLists())));
        }for (int i = 0; i < mLineDataSetList.size(); i++) {Path bezierPath = new Path();//曲线路径
            bezierPath.moveTo(mBezierLineDataList.get(i).get(0).getStartP().x, mBezierLineDataList.get(i).get(0).getStartP().y);
            for (int j = 0; j < mBezierLineDataList.get(i).size(); j++) {bezierPath.cubicTo(mBezierLineDataList.get(i).get(j).getCp1().x, mBezierLineDataList.get(i).get(j).getCp1().y,
                        mBezierLineDataList.get(i).get(j).getCp2().x, mBezierLineDataList.get(i).get(j).getCp2().y,
                        mBezierLineDataList.get(i).get(j).getEndP().x, mBezierLineDataList.get(i).get(j).getEndP().y);
            }//设置颜色和渐变
            int lineColor = mLineDataSetList.get(i).getColor();
            mBezierPaint.setColor(lineColor);
            LinearGradient mLinearGradient;
            int[] colorArr;
            if (mLineDataSetList.get(i).getGradientColors() != null) {colorArr = mLineDataSetList.get(i).getGradientColors();
            } else {colorArr = new int[]{lineColor, lineColor, lineColor, lineColor, lineColor};
            }mLinearGradient = new LinearGradient(mBezierLineDataList.get(i).get(0).getStartP().x,
                    0,
                    mBezierLineDataList.get(i).get(0).getEndP().x,
                    0,
                    colorArr,
                    null,
                    Shader.TileMode.CLAMP
            );
            mBezierPaint.setShader(mLinearGradient);
            canvas.drawPath(bezierPath, mBezierPaint);
            canvas.save();

            if (isChoocePoint && isNeedPoint) {//绘制数据点未选中点的圆点
                mCirclePaint.setColor(Color.RED);
                mCirclePaint.setStrokeWidth(1);
                mCirclePaint.setStyle(Paint.Style.FILL);
                if (cy != -1 && cy != -1)canvas.drawCircle(cx, cy, DensityUtil.dip2px(getContext(), 5), mCirclePaint);
            } else if (isNeedPoint) {//绘制数据点未选中点的圆点
            }}}/**
     * @param canvas
     */
    private void drawMark(Canvas canvas) {if (mPosition == -1 || mPosition == mOriginDataList.size()) return;
        mMarkPaint.setTextSize(DensityUtil.dip2px(getContext(), 12));

        float width = mMarkPaint.measureText(mCurrentData);
        float height = DensityUtils.getFontHeight(mMarkPaint);

        RectF rectF = new RectF();
        rectF.left = cx - width;
        rectF.top = cy - height;
        rectF.right = cx + width;
        rectF.bottom = cy + height;
        mMarkPaint.setColor(mMarkColor);
        canvas.drawRoundRect(rectF, 10, 10, mMarkPaint);
        mMarkPaint.setColor(Color.WHITE);
        canvas.drawText(mCurrentData, cx - width / 2, cy + height / 4, mMarkPaint);

    }/**
     * 把数据点转为 Android中的视图坐标
     *
     * @param oldPointFs
     * @return
     */
    private List<PointF> changePoint(int index, List<PointF> oldPointFs) {List<PointF> pointFs = new ArrayList<>();
        float maxValueY = 0;
        float yValue;
        PointF p;
        float x;
        float y;
        float totalHeight = mMinYPointF.y - mMaxYPointF.y - 2 * mMarginTopBottom;
        float dataLenght = mMaxYValue;
        for (int i = 0; i < oldPointFs.size(); i++) {PointF pointF = oldPointFs.get(i);
            //最后的正负值是左移右移
            x = xvalPointF.get(index).x + i * (xvalPointF.get(1).x - xvalPointF.get(0).x);
            y = mMinYPointF.y - totalHeight * pointF.y / dataLenght + mMarginTopBottom;
            p = new PointF(x, y);
            pointFs.add(p);
        }return pointFs;
    }/**
     * 利用三阶贝塞尔曲线,获取每一段曲线所需要的点集,包括开始点,结束点,两个控制点。
     *
     * @param pointList 所有的数据点
     * @return
     */
    private List<BezierLineData> bezierLineData(List<PointF> pointList) {float t = 0.5f;//比例
        List<BezierLineData> lineDataList = new ArrayList<>();
        PointF startP;
        PointF endP;
        PointF cp1;
        PointF cp2;
        BezierLineData lineData;
        for (int i = 0; i < pointList.size() - 1; i++) {startP = pointList.get(i);
            endP = pointList.get(i + 1);

            cp1 = new PointF();//控制点在水平方向,
            cp1.x = startP.x + (endP.x - startP.x) * t;
            cp1.y = startP.y;

            cp2 = new PointF();
            cp2.x = startP.x + (endP.x - startP.x) * (1 - t);
            cp2.y = endP.y;
            lineData = new BezierLineData(startP, endP, cp1, cp2);
            lineDataList.add(lineData);
        }return lineDataList;
    }/**
     * mXNameListShow是横坐标的集合,默认10个以下的数据,通过外部获取
     * 设置底部时间数据
     */
    public void setxDataList(List<String> xNameDataList) {if (xNameDataList.size() == 0) {return;
        }float textWidth = mXPaint.measureText(mXNameList.get(0));
        if (mMarginLeftRight == 0 || mMarginLeftRight < textWidth / 2f) {mMarginLeftRight = textWidth / 2;
        }this.mXNameList = xNameDataList;
    }public void setYDataList(List<PointF> points) {if (points.size() == 0) return;
        this.mOriginDataList = points;
        setmLineDataSetList(mOriginDataList);
    }/**
     * 设置Y轴数据
     *
     * @param points
     */
    private void setmLineDataSetList(List<PointF> points) {this.mLineDataSetList.clear();
        List<PointF> pointFLists;
        LineDataSet lineDataSet;
        for (int i = 0; i < points.size() - 1; i++) {lineDataSet = new LineDataSet();
            pointFLists = new ArrayList<>();
            pointFLists.add(points.get(i));
            if (i == points.size() - 1) {pointFLists.add(points.get(i));
            } else {pointFLists.add(points.get(i + 1));
            }lineDataSet.setColor(0xFFFF0000);
            lineDataSet.setGradientColors(mGradientColors);
            lineDataSet.setOldPointFLists(pointFLists);
            mLineDataSetList.add(lineDataSet);

            if (mMinYValue == 0) {mMinYValue = points.get(i).y;
            } else if (points.get(i).y < mMinYValue) {mMinYValue = points.get(i).y;
            }if (mMaxYValue == 0) {mMaxYValue = points.get(i).y;
            } else if (points.get(i).y > mMaxYValue) {mMaxYValue = points.get(i).y;
            }}if (mMaxYValue == 0) {mMaxYValue = 1;
        }float textWidth = mYPaint.measureText(mMaxYValue + "");
        if (mMarginLeftRight == 0 || mMarginLeftRight < textWidth / 2f) {mMarginLeftRight = textWidth / 2;
        }postInvalidate();
    }/**
     * 把数据点转为 Android中的视图坐标
     *
     * @param oldPointFs
     * @return
     */
    private List<PointF> changePoint(List<PointF> oldPointFs) {mNewDataList.clear();
        float maxValueY = 0;
        float yValue;
        PointF p;
        float x;
        float y;
        float totalHeight = mMinYPointF.y - mMaxYPointF.y - 2 * mMarginTopBottom;
        float dataLenght = mMaxYValue;
        for (int i = 0; i < oldPointFs.size(); i++) {PointF pointF = oldPointFs.get(i);
            //最后的正负值是左移右移
            x = i;
            y = mMinYPointF.y - totalHeight * pointF.y / dataLenght + mMarginTopBottom;
            p = new PointF(x, y);
            mNewDataList.add(p);
        }return mNewDataList;
    }@Override
    public boolean onTouchEvent(MotionEvent event) {float downX = event.getX();
        float downY = event.getY();
        switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mDownX = downX;
                cy = -1;
                cx = -1;
                //postInvalidateDelayed(50);
                Log.d(TAG, "onTouchEvent: ACTION_DOWN mDownX = " + mDownX);
                mPosition = -1;
                isChoocePoint = false;
                break;
            case MotionEvent.ACTION_MOVE:Log.d(TAG, "onTouchEvent: ACTION_MOVE mDownX = " + mDownX);
                mDownX = event.getX();
                invalidate();
                //postInvalidateDelayed(50);
                break;
            case MotionEvent.ACTION_UP:mPosition = 0;
                for (PointF p : mNewDataList) {if (Math.abs(downX - xvalPointF.get(mPosition).x) <= DensityUtil.dip2px(getContext(), 10)&& Math.abs(downY - p.y) <= DensityUtil.dip2px(getContext(), 10)) {isChoocePoint = true;
                        cx = xvalPointF.get(mPosition).x;
                        cy = p.y;
                        mCurrentData = mOriginDataList.get(mPosition).y + "";
                        Log.d("onTouchEvent: ", "mPosition: " + mPosition + " mCurrentData: " + mCurrentData);
                        postInvalidate();
                        continue;
                    }mPosition++;
                }break;
            case MotionEvent.ACTION_CANCEL:cx = -1;
                cy = -1;
                invalidate();
                break;
        }//postInvalidateDelayed(50);
        return true;
    }
}
<declare-styleable name="LineChartView">
    <attr name="maxvalue" format="dimension" />
    <attr name="bezier_line_width" format="dimension" />
    <attr name="bg_line_width" format="dimension" />
    <attr name="minvalue" format="dimension" />
    <attr name="markHeight" format="dimension" />

    <attr name="markWidth" format="dimension" />
    <attr name="markTextSize" format="dimension" />
    <attr name="yTextSize" format="dimension" />
    <attr name="xTextSize" format="dimension" />

    <attr name="yTextColor" format="color" />
    <attr name="xTextColor" format="color" />
    <attr name="lineTextColor" format="color" />
    <attr name="xLineTextColor" format="color" />
</declare-styleable>

Android-自定义贝塞尔曲线图表控件 渐近色相关推荐

  1. WPF 曲线图表控件(自制)(二)

    原文:WPF 曲线图表控件(自制)(二) 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/koloumi/article/details/775218 ...

  2. WPF 曲线图表控件(自制)(一)

    由于公司需要所以自写了一个简单的曲线图表控件,在此分享.先上一张效果图 1.界面xaml X轴和Y轴用 2个line对象写死在xaml上 外部用一个Grid包裹起来,然后X轴的宽度,和Y轴的高度就是绑 ...

  3. Android自定义一个播放器控件

    介绍 最近要使用播放器做一个简单的视频播放功能,开始学习VideoView,在横竖屏切换的时候碰到了点麻烦,不过在查阅资料后总算是解决了.在写VideoView播放视频时候定义控制的代码全写在Actv ...

  4. Android 自定义日期段选择控件,开始日期-结束日期。

    开发中碰到个需求,需要在一个控件中选择完成开始和结束日期.实现的过程走的是程序员开发的老路子,找到轮子后自己改吧改吧就成了.去年做的找不到参考的文章连接了,请原博主见谅. 当时做的时候有几个需求:1. ...

  5. Android 自定义底部上拉控件的实现

    前言 又到了新的一月,今天提供一个Android自定义底部上拉布局的实现,起因是自己在项目中需要实现这样一个控件,干脆自己写一个练练手. 写完了觉得能想到的需求都基本有了(可能会有其它需求,不过基本上 ...

  6. Android自定义滑动接听电话控件组

    一.目录结构 二.运行效果 三.代码实现 首先,自定义一个类IncomingPhone继承RelativeLayout public IncomingPhone(Context context, At ...

  7. Android自定义多TAB悬浮控件实现蘑菇街首页效果

    原文:http://www.cnblogs.com/ImyFen/archive/2015/11/15/4967127.html 说明: 1.viewpager不能左右滑动: 2.转载时代码略有改动( ...

  8. android自定义view圆,Android自定义View圆形百分比控件(一)

    做一个自定义View的小练习,效果如下 只需要画一个圆.一个圆弧.一个百分比文本,添加一个点击事件,传入百分比重绘 1.在res/values文件夹下新建attrs.xml文件,编写自定义属性: 2. ...

  9. android 星级评论,Android自定义RatingBar(星级评分控件)

    1.首先在Drawable下建立five_rating_bar.xml android:id="@android:id/background" android:drawable=& ...

最新文章

  1. android5多窗口,教程 开启 Nexus5 Android M 的多窗口模式。
  2. 扎格伯克败走加密货币:2亿美元打包变卖技术,核心团队出走殆尽,发币计划仅2年就从入门到放弃...
  3. Tracer Druid 记录sql 以及参数
  4. boost::hana::any_of用法的测试程序
  5. Java高并发之锁优化
  6. 设计模式之四(抽象工厂模式第三回合)
  7. 在gitee上创建自己的仓库步骤
  8. 前端学习(3167):react-hello-react之鼠标移入效果
  9. Spring Data JPA 从入门到精通~@Version处理乐观锁的问题
  10. 调用多个thrift接口ttypes冲突的问题
  11. 接口测试用例模板_《测试用例知识大全》----测试用例所有疑问,只需这篇就够了...
  12. 浅谈PHP-FPM参数
  13. 什么软件可以在给多个视频添加马赛克同时批量裁剪画面呢?
  14. 阿里云服务器如何登录?阿里云服务器的三种登录方法
  15. java猜拳小游戏心得体会_java实现猜拳小游戏
  16. sqlserver转mysql_数据库 SQLServer转MySQL数据库
  17. teamviewer远程黑屏问题
  18. 【数学建模】多元线性回归(PythonMatlab代码实现)
  19. 免费版软件文档文件格式转换
  20. Linux驱动开发(一)

热门文章

  1. 桶装水价格表 it 计算机,桶装水配送价格价格如何计算?「大力水手」
  2. Node.js 进程管理工具
  3. 超链接——内部链接、外部链接、锚点链接、下载链接、空链接、其他元素链接
  4. AD21.2新手快速上手(快捷键总结)线宽,覆铜minimu SolderMasksliver,silk to solder mask clearance,silk to sill clearan设置
  5. 进退维“谷”:华人创业者的困境和机遇
  6. 钉钉之最终幻想:No App
  7. css镂空三角形样式
  8. 数据可视化:对比漏斗图多维度分析大学在校实际开销情况
  9. 06 对包进行分类的高级过滤器
  10. ASP.NET 网页中的跨页发送PreviousPage