Setting下的自定义控件LinearColorBar

来源:互联网 发布:linux 清空arp缓存 编辑:程序博客网 时间:2024/04/29 18:23
  版本:1.0
  日期:2014.3.21
  版权:©  2013,2014 kince 转载注明出处

  Setting应用下使用了不少自定义控件,比如这些效果:
流量显示
  
电量显示

存储空间显示

  先介绍最后这个存储空间显示的LinearColorBar,通过名字就可以看出是是继承于LinearLayout,确实也是如此。分析一下这个效果,在控件的左边显示已经使用了多少空间,右边是所有可用空间。上面还有所显示的类别,RAM。当然最主要的还是那个环形的效果。看一下LinearColorBar的实现代码:
/****/package com.example.settingscustomviewdemo.widget;import android.content.Context;import android.graphics.Canvas;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.Path;import android.graphics.Rect;import android.graphics.Shader;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.widget.LinearLayout;public class LinearColorBar extends LinearLayout {        static final int LEFT_COLOR = 0xff0099cc;    static final int MIDDLE_COLOR = 0xff0099cc;    static final int RIGHT_COLOR = 0xff888888;       private float mRedRatio;    private float mYellowRatio;    private float mGreenRatio;    private boolean mShowingGreen;    final Rect mRect = new Rect();    final Paint mPaint = new Paint();    int mLastInterestingLeft, mLastInterestingRight;    int mLineWidth;    final Path mColorPath = new Path();    final Path mEdgePath = new Path();    final Paint mColorGradientPaint = new Paint();    final Paint mEdgeGradientPaint = new Paint();    public LinearColorBar(Context context, AttributeSet attrs) {        super(context, attrs);        setWillNotDraw(false);        mPaint.setStyle(Paint.Style.FILL);        mColorGradientPaint.setStyle(Paint.Style.FILL);        mColorGradientPaint.setAntiAlias(true);        mEdgeGradientPaint.setStyle(Paint.Style.STROKE);        mLineWidth = getResources().getDisplayMetrics().densityDpi >= DisplayMetrics.DENSITY_HIGH                ? 2 : 1;        mEdgeGradientPaint.setStrokeWidth(mLineWidth);        mEdgeGradientPaint.setAntiAlias(true);           }    public void setRatios(float red, float yellow, float green) {        mRedRatio = red;        mYellowRatio = yellow;        mGreenRatio = green;        invalidate();    }    public void setShowingGreen(boolean showingGreen) {        if (mShowingGreen != showingGreen) {            mShowingGreen = showingGreen;            updateIndicator();            invalidate();        }    }    private void updateIndicator() {        int off = getPaddingTop() - getPaddingBottom();        if (off < 0) off = 0;        mRect.top = off;        mRect.bottom = getHeight();        if (mShowingGreen) {            mColorGradientPaint.setShader(new LinearGradient(                    0, 0, 0, off-2, RIGHT_COLOR&0xffffff, RIGHT_COLOR, Shader.TileMode.CLAMP));        } else {            mColorGradientPaint.setShader(new LinearGradient(                    0, 0, 0, off-2, MIDDLE_COLOR&0xffffff, MIDDLE_COLOR, Shader.TileMode.CLAMP));        }        mEdgeGradientPaint.setShader(new LinearGradient(                0, 0, 0, off/2, 0x00a0a0a0, 0xffa0a0a0, Shader.TileMode.CLAMP));    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        updateIndicator();    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        int width = getWidth();        int left = 0;        int right = left + (int)(width*mRedRatio);        int right2 = right + (int)(width*mYellowRatio);        int right3 = right2 + (int)(width*mGreenRatio);        int indicatorLeft, indicatorRight;        if (mShowingGreen) {            indicatorLeft = right2;            indicatorRight = right3;        } else {            indicatorLeft = right;            indicatorRight = right2;        }        if (mLastInterestingLeft != indicatorLeft || mLastInterestingRight != indicatorRight) {            mColorPath.reset();            mEdgePath.reset();            if (indicatorLeft < indicatorRight) {                final int midTopY = mRect.top;                final int midBottomY = 0;                final int xoff = 2;                mColorPath.moveTo(indicatorLeft, mRect.top);                mColorPath.cubicTo(indicatorLeft, midBottomY,                        -xoff, midTopY,                        -xoff, 0);                mColorPath.lineTo(width+xoff-1, 0);                mColorPath.cubicTo(width+xoff-1, midTopY,                        indicatorRight, midBottomY,                        indicatorRight, mRect.top);                mColorPath.close();                final float lineOffset = mLineWidth+.5f;                mEdgePath.moveTo(-xoff+lineOffset, 0);                mEdgePath.cubicTo(-xoff+lineOffset, midTopY,                        indicatorLeft+lineOffset, midBottomY,                        indicatorLeft+lineOffset, mRect.top);                mEdgePath.moveTo(width+xoff-1-lineOffset, 0);                mEdgePath.cubicTo(width+xoff-1-lineOffset, midTopY,                        indicatorRight-lineOffset, midBottomY,                        indicatorRight-lineOffset, mRect.top);            }            mLastInterestingLeft = indicatorLeft;            mLastInterestingRight = indicatorRight;        }        if (!mEdgePath.isEmpty()) {            canvas.drawPath(mEdgePath, mEdgeGradientPaint);            canvas.drawPath(mColorPath, mColorGradientPaint);        }        if (left < right) {            mRect.left = left;            mRect.right = right;            mPaint.setColor(LEFT_COLOR);            canvas.drawRect(mRect, mPaint);            width -= (right-left);            left = right;        }        right = right2;        if (left < right) {            mRect.left = left;            mRect.right = right;            mPaint.setColor(MIDDLE_COLOR);            canvas.drawRect(mRect, mPaint);            width -= (right-left);            left = right;        }        right = left + width;        if (left < right) {            mRect.left = left;            mRect.right = right;            mPaint.setColor(RIGHT_COLOR);            canvas.drawRect(mRect, mPaint);        }    }}
  读完源码看一下它的变量,画笔Paint不说了,用于设置笔触的样式。除此之外就是Rect和Path了,关于这两个类的功能,其实从字面意思大体可以猜得出来。Rect是用于绘制矩形的,Path则用于画线,包括直线、二次曲线、三次曲线等。那从这两个类的用途就不难猜出它们各自在LinaerColorBar中的作用了,Rect用于绘制使用了多少空间的进度条,Path则是用于绘制那个二次型图案。
  然后直接进入Draw()方法,开始初始化一些变量,这些变量之后会使用到。
          int width = getWidth();//获取组件宽度          int left = 0;          //          int right = left + (int) (width * mRedRatio);//          int right2 = right + (int) (width * mYellowRatio);//          int right3 = right2 + (int) (width * mGreenRatio);//          int indicatorLeft, indicatorRight;          if (mShowingGreen) {               indicatorLeft = right2;               indicatorRight = right3;          } else {               indicatorLeft = right;               indicatorRight = right2;          }
  这几个right值就是根据设置的空间使用大小转换而来的,其实就是控件宽度的比例值,在画Rect的时候传入即可。接着往下看,
                    mColorPath.moveTo(indicatorLeft, mRect.top);                    mColorPath.cubicTo(indicatorLeft, midBottomY, -xoff, midTopY,                              -xoff, 0);                    mColorPath.lineTo(width + xoff - 1, 0);                    mColorPath.cubicTo(width + xoff - 1, midTopY, indicatorRight,                              midBottomY, indicatorRight, mRect.top);                    mColorPath.close();
  
  
  这段代码就是用于画这个弧形的,首先moveTo()方法,将画笔移动到这个点,然后使用cubicTo方法画一个二次曲线,因为画笔设置了Paint.Style.FILL,所以看起来像是一片的效果,而不是直线。
                    final float lineOffset = mLineWidth + .5f;                    mEdgePath.moveTo(-xoff + lineOffset, 0);                    mEdgePath.cubicTo(-xoff + lineOffset, midTopY, indicatorLeft                              + lineOffset, midBottomY, indicatorLeft + lineOffset,                              mRect.top);                    mEdgePath.moveTo(width + xoff - 1 - lineOffset, 0);                    mEdgePath.cubicTo(width + xoff - 1 - lineOffset, midTopY,                              indicatorRight - lineOffset, midBottomY, indicatorRight                                        - lineOffset, mRect.top);
  这段代码用于在之前的基础上描边,

  这样,弧形效果就实现了。然后就是下面的矩形了,
if (left < right) {               mRect.left = left;               mRect.right = right;               mPaint.setColor(LEFT_COLOR);               canvas.drawRect(mRect, mPaint);               width -= (right - left);               left = right;          }          right = right2;          if (left < right) {               mRect.left = left;               mRect.right = right;               mPaint.setColor(MIDDLE_COLOR);               canvas.drawRect(mRect, mPaint);               width -= (right - left);               left = right;          }          right = left + width;          if (left < right) {               mRect.left = left;               mRect.right = right;               mPaint.setColor(RIGHT_COLOR);               canvas.drawRect(mRect, mPaint);          }
  这个就相对简单了,用Rect直接画就行了。
  总结:这个自定义的控件是继承于系统原有的容器控件LinearLayout,为什么要选择LinearLayout呢,其实也可以是RelativeLayout,容器控件都可以,只要把那三个TextView安放好位置就行。然后就是绘图了,这里结合了Paint、Path、Rect以及Canvas的使用,其实自定义控件很多时候就是使用这几个类,所以对这几个类的掌握尤为重要。那最后就是逻辑,这也是很重要的一个部分,对于效果我们可能想到使用什么类去实现,那对于效果的控制与变化就需要依靠逻辑了。

  demo下载

5 0
原创粉丝点击