編輯:關於Android編程
最近工作繁忙,一直都埋頭在工作中,也不知這麼熱心工作究竟是為了什麼,不知不覺的,到今天才曉得夏天已經來了。天氣熱,心也熱。
網絡上出個牛人,辭職信上寫著:世界那麼大,我想去看看。由衷的佩服她的勇氣,我也想去看看這大千世界,可惜我們總是身不由己,有太多的放不下,或許哪天放下了,我也出去走走。
之前一直以為羅永浩是個逗比,直到前兩天看了他幾期演講,才發現逗比一直是我。他有句話我很欣賞,這裡也分享給大家:在什麼樣的年紀,就做什麼樣的事情,怎麼能在每個階段都做錯呢!PS:該玩的年紀玩,該談戀愛的年紀談戀愛,該成家立業擔起一個家的年紀就要挺起胸膛,總不能錯過玩的年紀,錯過談戀愛的年紀,而成家後卻又搞外遇,怎麼能在每個階段都做錯呢?
在我有那個勇氣也在辭職信上寫著“世界那麼大,我也想去看看!”之前,還是要把眼前的事情做完,現在開始規劃。
正文
Android進度條是很多人都接觸到的,然而面對各種各樣的需求時,原生的很多東西都滿足不了我們的需要,在各種壓迫下,大家都選擇自定義來解決問題。今天給大家介紹一下自定義進度條。
提到自定義,這曾經一直是使我頭疼的問題,看過很多大牛的源碼之後,發現一個道理,有些代碼不應該記住,而有些代碼也不應該忘記。所以我決定,今天的博客裡給大家分享方法。(其實是代碼邏輯實在是太糟糕了,我寫過後回頭看的時候都不知道自己為什麼那麼寫,而且還必須那麼寫,哈哈。)
首先我們要知道自定義View中那些方法是我們需要用到的。
構造方法:
構造方法是必不可少的,所有在View對象一出來就需要存在的都要在這裡初始化。這裡就不多說了。
onDraw
@Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); }
onSizeChanged
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); }
以上這三個,就可以完成常規的自定義組件,往往我們的業務邏輯上,需要加上很多事件,比如onclick,ontouch等。用到這些事件監聽時,通常需要invalidate方法來在需要的時候刷新界面。
需要注意的是,每個方法的執行順序,建議大家自己用log日志實驗一下。方便記憶。
接下來開始貼代碼,現在大多數需求都是圓角進度條,這裡也以此為例。
onDraw方法是用來繪制任何我們需要的東西的,所以進度條也在此繪制,我將進度條矩形抽取出一個方法,方便復用。
/** * 繪制矩形 * * @param canvas * @param paint * @param left * 左 * @param top * 上 * @param right * 右 * @param bottom * 下 */ private void drawRect(Canvas canvas, Paint paint, float left, float top, float right, float bottom) { RectF rectF = new RectF(left, top, right, bottom); if (isRoundRect) { canvas.drawRoundRect(rectF, mRadius, mRadius, paint); } else { canvas.drawRect(rectF, paint); } }
好了,我們的自定義進度條講完了。
但是這也就是純粹的進度條了,需要對應的set和get方法來設置和獲取值。set後,記得調用invalidate方法來重繪界面。
我的進度條有拖拽功能,先繪制拖拽的圓圈。
/** * 繪制拖動點 * @param canvas */ private void drawDragClick(Canvas canvas) { mDragClickPaint.setColor(Color.BLACK); RectF oval = new RectF(mAboveProgressWidth - mDragClickPaintRadius, mStartY + mProgressRealHeight/2 - mDragClickPaintRadius, mAboveProgressWidth + mDragClickPaintRadius, mStartY + mProgressRealHeight/2 + mDragClickPaintRadius); canvas.drawOval(oval, mDragClickPaint); mDragClickPaint.setColor(Color.WHITE); RectF oval2 = new RectF(mAboveProgressWidth - mDragClickPaintRadius + 1, mStartY + mProgressRealHeight/2 - mDragClickPaintRadius + 1, mAboveProgressWidth + mDragClickPaintRadius - 1, mStartY + mProgressRealHeight/2 + mDragClickPaintRadius - 1); canvas.drawOval(oval2, mDragClickPaint); }
private boolean isActionUp; @Override public boolean onTouch(View v, MotionEvent event) { int code = event.getAction(); // Log.i("progress", "onTouch"+mAboveProgressWidth); switch (code) { case MotionEvent.ACTION_DOWN: isActionUp = false; setOnTouchInit(event); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: isActionUp = true; setOnTouchInit(event); break; case MotionEvent.ACTION_MOVE: isActionUp = false; setOnTouchInit(event); break; } return true; } /** * 觸摸時設置邊界 */ private void setOnTouchInit(MotionEvent event){ if (isTransfer) { if (event.getX() < mDragClickPaintRadius) { mAboveProgressWidth = mDragClickPaintRadius; }else if (event.getX() > mCenterProgressWidth) { mAboveProgressWidth = mCenterProgressWidth; // Log.i("progress", "onTouch"+mAboveProgressWidth + "***" + mCenterProgressWidth); }else { mAboveProgressWidth = event.getX(); } }else { if (event.getX() < mDragClickPaintRadius) { mAboveProgressWidth = mDragClickPaintRadius; }else if (event.getX() > mWidth - mDragClickPaintRadius) { mAboveProgressWidth = mWidth - mDragClickPaintRadius; }else { mAboveProgressWidth = event.getX(); } } mFirstValue = mMaxValue *( mAboveProgressWidth - mDragClickPaintRadius) / mDrawScaleWidth; if (mDragListener != null && isActionUp) { mDragListener.onDrag(this, getmFirstValue()); } invalidate(); }
貼上全部的控件代碼
package com.qiyuan.activity.view; import java.util.Collections; import java.util.List; import android.R.integer; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.FontMetrics; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.View.OnClickListener; /** * 可以拖動的進度條 * * @author lizhipeng * */ public class CanDragProgressView extends View implements OnTouchListener,OnClickListener{ private int mWidth, mHeight;// 整個的寬和高 private long mDrawScaleWidth;// 畫刻度時用的寬度(兩邊減去拖動點半徑的寬度) private int mScaleHeight = 10;// 刻度線的高度 private int mProgressHeight;// 進度條的相對高度 private float mProgressRealHeight = 40;//進度條真實高度 private int mAverageScaleNumber = 10;// 設置均分刻度的個數(多少個單位) private int mScaleLineWidth, mScalerLineHeight;// 刻度線寬高 private int mRadius;// 進度條圓角半徑 private float mDragClickPaintRadius;// 拖動點半徑 private float mStartX; private float mStartY = 5; private float mFirstValue;//顯示在拖動條上的值 private float mSecondValue;//第二個值 private float mBgProgressWidth, mCenterProgressWidth, mAboveProgressWidth;// 背景、中間、上層進度條寬度(長度) private Paint mBackgroundPaint, mCenterPaint, mAbovePaint, mScalePaint, mDragClickPaint;// 背景畫筆,中間層畫筆,上層畫筆、刻度線、拖動點 private boolean isRoundRect = true;// 是否是圓角矩形 private boolean isAverageScale = true;// 是否均分刻度,如果不均分刻度,需要用設置刻度的集合mScaleList private boolean isDrawScaleUp = false;// 繪制刻度在進度條上或者下,默認是下 private boolean isDrawScale = true;// 是否繪制刻度 private boolean isDrawCenterScale = false;// 是否繪制中間部分的刻度 private boolean isTransfer = false;// 是否是Transfer界面 private float mMaxValue;//最大值 private ListmScaleList; private DragListener mDragListener;//滑動監聽 public interface DragListener{ public void onDrag(CanDragProgressView view,float value); } public DragListener getmDragListener() { return mDragListener; } public void setmDragListener(DragListener mDragListener) { this.mDragListener = mDragListener; } public boolean isTransfer() { return isTransfer; } public void setTransfer(boolean isTransfer) { this.isTransfer = isTransfer; invalidate(); } public boolean isDrawCenterScale() { return isDrawCenterScale; } public void setDrawCenterScale(boolean isDrawCenterScale) { this.isDrawCenterScale = isDrawCenterScale; invalidate(); } public float getmSecondValue() { return mSecondValue; } public void setmSecondValue(float mSecondValue) { this.mSecondValue = mSecondValue; invalidate(); } public float getmFirstValue() { return Float.parseFloat(String.format("%1.2f", mFirstValue)); } public void setmFirstValue(float mValue) { this.mFirstValue = mValue; invalidate(); } public List getmScaleList() { return mScaleList; } public void setmScaleList(List list) { Collections.sort(list); this.mScaleList = list; invalidate(); } public float getmProgressRealHeight() { return mProgressRealHeight; } public void setmProgressRealHeight(float mProgressRealHeight) { this.mProgressRealHeight = mProgressRealHeight; invalidate(); } public void setmScaleHeight(int mScaleHeight) { this.mScaleHeight = mScaleHeight; invalidate(); } public boolean isDrowScaleUp() { return isDrawScaleUp; } public void setDrowScaleUp(boolean isDrowScaleUp) { this.isDrawScaleUp = isDrowScaleUp; mStartY = mScaleHeight + getFontHeight(mScalePaint) + 5; invalidate(); } public int getmAverageScaleNumber() { return mAverageScaleNumber; } public void setmAverageScaleNumber(int mAverageScaleNumber) { this.mAverageScaleNumber = mAverageScaleNumber; invalidate(); } public int getmScaleLineWidth() { return mScaleLineWidth; } public void setmScaleLineWidth(int mScaleLineWidth) { this.mScaleLineWidth = mScaleLineWidth; invalidate(); } public int getmScalerLineHeight() { return mScalerLineHeight; } public void setmScalerLineHeight(int mScalerLineHeight) { this.mScalerLineHeight = mScalerLineHeight; invalidate(); } public boolean isAverageScale() { return isAverageScale; } public void setAverageScale(boolean isAverageScale) { this.isAverageScale = isAverageScale; invalidate(); } // private int getmWidth() { // return mWidth; // } // // private void setmWidth(int mWidth) { // this.mWidth = mWidth; // } public int getmHeight() { return mHeight; } public void setmHeight(int mHeight) { this.mHeight = mHeight; } public int getmProgressHeight() { return mProgressHeight; } public void setmProgressHeight(int mProgressHeight) { this.mProgressHeight = mProgressHeight; invalidate(); } public int getmRadius() { return mRadius; } public void setmRadius(int mRadius) { this.mRadius = mRadius; invalidate(); } public float getmBgProgressWidth() { return mBgProgressWidth; } public void setmBgProgressWidth(float mBgProgressWidth) { this.mBgProgressWidth = mBgProgressWidth; invalidate(); } public float getmCenterProgressWidth() { return mCenterProgressWidth; } public void setmCenterProgressWidth(float mCenterProgressWidth) { this.mCenterProgressWidth = mCenterProgressWidth; invalidate(); } public float getmAboveProgressWidth() { return mAboveProgressWidth; } public void setmAboveProgressWidth(float mAboveProgressWidth) { this.mAboveProgressWidth = mAboveProgressWidth; invalidate(); } // ------------------------------------------------------------------Paint------------------ public Paint getmDragClickPaint() { return mDragClickPaint; } public void setmDragClickPaint(Paint mDragClickPaint) { initPain(mDragClickPaint); this.mDragClickPaint = mDragClickPaint; invalidate(); } public Paint getmScalePaint() { return mScalePaint; } public void setmScalePaint(Paint mScalePaint) { initPain(mScalePaint); this.mScalePaint = mScalePaint; invalidate(); } public Paint getmBackgroundPaint() { return mBackgroundPaint; } public void setmBackgroundPaint(Paint mBackgroundPaint) { initPain(mBackgroundPaint); this.mBackgroundPaint = mBackgroundPaint; invalidate(); } public Paint getmCenterPaint() { return mCenterPaint; } public void setmCenterPaint(Paint mCenterPaint) { initPain(mCenterPaint); this.mCenterPaint = mCenterPaint; invalidate(); } public Paint getmAbovePaint() { return mAbovePaint; } public void setmAbovePaint(Paint mAbovePaint) { initPain(mAbovePaint); this.mAbovePaint = mAbovePaint; invalidate(); } // ------------------------------------------------------------------Paint------------------ public boolean isRoundRect() { return isRoundRect; } public void setRoundRect(boolean isRoundRect) { this.isRoundRect = isRoundRect; invalidate(); } public float getmMaxValue() { return mMaxValue; } public void setmMaxValue(float mMaxValue) { this.mMaxValue = mMaxValue; invalidate(); } public CanDragProgressView(Context context) { super(context); // TODO Auto-generated constructor stub init(); } public CanDragProgressView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(); } public CanDragProgressView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub init(); } /** * 初始化 */ private void init() { mBackgroundPaint = new Paint(); mBackgroundPaint.setColor(Color.GRAY); mScalePaint = new Paint(); mScalePaint.setColor(Color.GRAY); mScalePaint.setTextSize(16); mCenterPaint = new Paint(); mCenterPaint.setColor(Color.BLUE); mAbovePaint = new Paint(); mAbovePaint.setColor(Color.RED); mAbovePaint.setTextSize(45); mDragClickPaint = new Paint(); mDragClickPaint.setColor(Color.BLACK); this.setOnTouchListener(this); initPain(mDragClickPaint); initPain(mBackgroundPaint); initPain(mScalePaint); initPain(mCenterPaint); initPain(mAbovePaint); } /** * 初始化畫筆 * * @param paint */ private void initPain(Paint paint) { paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setAntiAlias(true);// 抗鋸齒效果 } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(widthMeasureSpec, 150); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub mWidth = w; mHeight = h; mBgProgressWidth = mWidth; mCenterProgressWidth = 2 * mBgProgressWidth / 3; if (isDrawScaleUp) { mStartY = mScaleHeight + getFontHeight(mScalePaint) + 5; mProgressHeight = (int) (getFontHeight(mScalePaint) + mScaleHeight + mProgressRealHeight + 5 + mStartY); } else { mStartY = 60; mProgressHeight = (int) (mProgressRealHeight + mStartY); } mDragClickPaintRadius = (float) (mProgressRealHeight / 2 + 15); mRadius = (int) (mProgressRealHeight / 2 + 5); mDrawScaleWidth = (long) (mWidth - 2 * mDragClickPaintRadius); mScaleHeight = 10; mAboveProgressWidth = (mDrawScaleWidth*(mFirstValue/mMaxValue) + mDragClickPaintRadius); mCenterProgressWidth = (mDrawScaleWidth*(mSecondValue/mMaxValue) + mDragClickPaintRadius); super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub // 繪制三個矩形 drawRect(canvas, mBackgroundPaint, 0, mStartY, mBgProgressWidth, mProgressHeight); // Log.i("progress", mBgProgressWidth+"**"+mProgressHeight+"**"+mStartY+"**"+getFontHeight(mScalePaint)); drawRect(canvas, mCenterPaint, 0, mStartY, mCenterProgressWidth, mProgressHeight); drawRect(canvas, mAbovePaint, 0, mStartY, mAboveProgressWidth, mProgressHeight); // 繪制刻度 drawScales(canvas); // 繪制拖動點 drawDragClick(canvas); // 繪制滾動數字 drawChangeValue(canvas); super.onDraw(canvas); } /** * 繪制滾動數字 * @param canvas */ private void drawChangeValue(Canvas canvas) { if (mAbovePaint.measureText(String.format("%1.2f", mFirstValue)) + mDrawScaleWidth*mFirstValue/mMaxValue > mWidth) { canvas.drawText(String.format("%1.2f", mFirstValue), mWidth - mAbovePaint.measureText(String.format("%1.2f", mFirstValue)), 3*getFontHeight(mAbovePaint)/4, mAbovePaint); }else { canvas.drawText(String.format("%1.2f", mFirstValue), mDrawScaleWidth*mFirstValue/mMaxValue, 3*getFontHeight(mAbovePaint)/4, mAbovePaint); } } /** * 繪制拖動點 * @param canvas */ private void drawDragClick(Canvas canvas) { mDragClickPaint.setColor(Color.BLACK); RectF oval = new RectF(mAboveProgressWidth - mDragClickPaintRadius, mStartY + mProgressRealHeight/2 - mDragClickPaintRadius, mAboveProgressWidth + mDragClickPaintRadius, mStartY + mProgressRealHeight/2 + mDragClickPaintRadius); canvas.drawOval(oval, mDragClickPaint); mDragClickPaint.setColor(Color.WHITE); RectF oval2 = new RectF(mAboveProgressWidth - mDragClickPaintRadius + 1, mStartY + mProgressRealHeight/2 - mDragClickPaintRadius + 1, mAboveProgressWidth + mDragClickPaintRadius - 1, mStartY + mProgressRealHeight/2 + mDragClickPaintRadius - 1); canvas.drawOval(oval2, mDragClickPaint); } /** * 繪制刻度 * * @param canvas */ private void drawScales(Canvas canvas) { if (isDrawScale) {// 是否繪制刻度 if (isAverageScale) {// 均分的刻度 long unitLenght = mDrawScaleWidth / mAverageScaleNumber;// 單位長度 if (isDrawScaleUp) { for (int i = 0; i < mAverageScaleNumber + 1; i++) { float startX = mDragClickPaintRadius + i * unitLenght; canvas.drawLine(startX, getFontHeight(mScalePaint), startX, mScaleHeight +getFontHeight(mScalePaint), mScalePaint); canvas.drawText(mMaxValue/mAverageScaleNumber*i+"", startX - mScalePaint.measureText(startX + "") / 2, getFontHeight(mScalePaint), mScalePaint); } } else { for (int i = 0; i < mAverageScaleNumber + 1; i++) { if (isDrawCenterScale) { float startX = mDragClickPaintRadius + i * unitLenght; float endY = mProgressHeight + 5 + mScaleHeight; canvas.drawLine(startX, mProgressHeight + 5, startX, endY, mScalePaint); canvas.drawText(mMaxValue/mAverageScaleNumber*i+"", startX - mScalePaint.measureText(startX + "") / 3, endY + getFontHeight(mScalePaint), mScalePaint); }else { if (i == 0 || i == mAverageScaleNumber) { float startX = mDragClickPaintRadius + i * unitLenght; float endY = mProgressHeight + 5 + mScaleHeight; canvas.drawLine(startX, mProgressHeight + 5, startX, endY, mScalePaint); canvas.drawText(mMaxValue/mAverageScaleNumber*i+"", startX - mScalePaint.measureText(startX + "") / 3, endY + getFontHeight(mScalePaint), mScalePaint); } } } } } else { if (isDrawScaleUp) { for (int i = 0; i < mScaleList.size(); i++) { double number = mScaleList.get(i); double unit = mDrawScaleWidth*(number/mMaxValue); float startX = (float) (mDragClickPaintRadius + unit); if (unit != 0) { canvas.drawLine(mDragClickPaintRadius, getFontHeight(mScalePaint), mDragClickPaintRadius, mScaleHeight +getFontHeight(mScalePaint), mScalePaint); canvas.drawText("0", mDragClickPaintRadius - mScalePaint.measureText("0") / 2, getFontHeight(mScalePaint), mScalePaint); } canvas.drawLine(startX, getFontHeight(mScalePaint), startX, mScaleHeight +getFontHeight(mScalePaint), mScalePaint); canvas.drawText(mScaleList.get(i)+"", startX - mScalePaint.measureText(""+mScaleList.get(i))/2, getFontHeight(mScalePaint), mScalePaint); } } else { for (int i = 0; i < mScaleList.size(); i++) { double number = mScaleList.get(i); double unit = mDrawScaleWidth*(number/mMaxValue); float startX = (float) (mDragClickPaintRadius + unit); float endY = mProgressHeight + 5 + mScaleHeight; if (unit != 0) { canvas.drawLine(mDragClickPaintRadius, mProgressHeight + 5, mDragClickPaintRadius, endY, mScalePaint); canvas.drawText("0", mDragClickPaintRadius - mScalePaint.measureText("0") / 2, endY + getFontHeight(mScalePaint), mScalePaint); } canvas.drawLine(startX, mProgressHeight + 5, startX, endY, mScalePaint); canvas.drawText(mScaleList.get(i)+"", startX - mScalePaint.measureText(""+mScaleList.get(i))/2, endY + getFontHeight(mScalePaint), mScalePaint); } } } } } /** * 繪制矩形 * * @param canvas * @param paint * @param left * 左 * @param top * 上 * @param right * 右 * @param bottom * 下 */ private void drawRect(Canvas canvas, Paint paint, float left, float top, float right, float bottom) { RectF rectF = new RectF(left, top, right, bottom); if (isRoundRect) { canvas.drawRoundRect(rectF, mRadius, mRadius, paint); } else { canvas.drawRect(rectF, paint); } } /** * 獲取繪制的字體高度 * * @param paint * @return */ private int getFontHeight(Paint paint) { FontMetrics fm = paint.getFontMetrics(); return (int) Math.ceil(fm.descent - fm.ascent); } private boolean isActionUp; @Override public boolean onTouch(View v, MotionEvent event) { int code = event.getAction(); // Log.i("progress", "onTouch"+mAboveProgressWidth); switch (code) { case MotionEvent.ACTION_DOWN: isActionUp = false; setOnTouchInit(event); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: isActionUp = true; setOnTouchInit(event); break; case MotionEvent.ACTION_MOVE: isActionUp = false; setOnTouchInit(event); break; } return true; } /** * 觸摸時設置邊界 */ private void setOnTouchInit(MotionEvent event){ if (isTransfer) { if (event.getX() < mDragClickPaintRadius) { mAboveProgressWidth = mDragClickPaintRadius; }else if (event.getX() > mCenterProgressWidth) { mAboveProgressWidth = mCenterProgressWidth; // Log.i("progress", "onTouch"+mAboveProgressWidth + "***" + mCenterProgressWidth); }else { mAboveProgressWidth = event.getX(); } }else { if (event.getX() < mDragClickPaintRadius) { mAboveProgressWidth = mDragClickPaintRadius; }else if (event.getX() > mWidth - mDragClickPaintRadius) { mAboveProgressWidth = mWidth - mDragClickPaintRadius; }else { mAboveProgressWidth = event.getX(); } } mFirstValue = mMaxValue *( mAboveProgressWidth - mDragClickPaintRadius) / mDrawScaleWidth; if (mDragListener != null && isActionUp) { mDragListener.onDrag(this, getmFirstValue()); } invalidate(); } @Override public void onClick(View v) { // TODO Auto-generated method stub } }
一、需求有時候應用需要在內部切換語言但又不影響系統的語言,比如是應用現在是中文的,系統語言也是中文的,我把應用的切換成英文顯示後系統語言還是中文的,系統語言切換後也不會被
前面的文章已經講述了隨手拍項目圖像處理的技術部分,該篇文章主要是主界面的布局及屏幕滑動切換,並結合鴻洋大神的視頻和郭神的第一行代碼(強推兩人Android博客),完成了下
好久沒有發博客了,現在工作忙了,底層代碼跟蹤學習的東西很久沒有做成文檔了,雖然博客寫的爛,但是再寫的過程中,能更清晰的認識到自己那個地方還不清晰,不明白。這樣能更好的嘴一
上一篇博文說到了Shader的五個子類 - BitmapShader - LinearGradient - RadialGradient - SweepGradient