編輯:關於Android編程
雖然只是模仿,但我覺得這是學習自定義view的必經之路,所以還是把我所學到的東西拿出來與大家一起分享。
先貼出一張progressBar的gif圖,其中有水平的進度條,和圓形的進度條:
這裡我們的實現的思路是繼承的progressBar,然後重新去測量和繪制相關代碼,我們直接貼出源碼:
package com.example.asiatravel.learnprogressbar.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.TypedValue; import android.widget.ProgressBar; import com.example.asiatravel.learnprogressbar.R; /** * Created by kuangxiaoguo on 16/9/8. * * 水平進度條 */ public class HorizontalProgressbarWithProgress extends ProgressBar { private static final int DEFAULT_TEXT_SIZE = 10; private static final int DEFAULT_TEXT_COLOR = 0xFFFC00D1; private static final int DEFAULT_COLOR_UNREACH = 0XFFD3D6DA; private static final int DEFAULT_HEIGHT_UNREACH = 2; private static final int DEFAULT_COLOR_REACH = DEFAULT_TEXT_COLOR; private static final int DEFAULT_HEIGHT_REACH = 2; private static final int DEFAULT_TEXT_OFFSET = 10; protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE); protected int mTextColor = DEFAULT_TEXT_COLOR; protected int mUnReachColor = DEFAULT_COLOR_UNREACH; protected int mUNReachHeight = dp2px(DEFAULT_HEIGHT_UNREACH); protected int mReachColor = DEFAULT_COLOR_REACH; protected int mReachHeight = dp2px(DEFAULT_HEIGHT_REACH); protected int mTextOffSet = dp2px(DEFAULT_TEXT_OFFSET); protected Paint mPaint = new Paint(); protected int mRealWidth; public HorizontalProgressbarWithProgress(Context context) { this(context, null); } public HorizontalProgressbarWithProgress(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HorizontalProgressbarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); obtainStyleAttrs(attrs); } /** * 獲取自定義屬性 */ private void obtainStyleAttrs(AttributeSet attrs) { TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressbarWithProgress); mTextSize = (int) ta.getDimension(R.styleable.HorizontalProgressbarWithProgress_progress_text_size, mTextSize); mTextColor = ta.getColor(R.styleable.HorizontalProgressbarWithProgress_progress_text_color, mTextColor); mUnReachColor = ta.getColor(R.styleable.HorizontalProgressbarWithProgress_progress_unreach_color, mUnReachColor); mUNReachHeight = (int) ta.getDimension(R.styleable.HorizontalProgressbarWithProgress_progress_unreach_height, mUNReachHeight); mReachColor = ta.getColor(R.styleable.HorizontalProgressbarWithProgress_progress_reach_color, mReachColor); mReachHeight = (int) ta.getDimension(R.styleable.HorizontalProgressbarWithProgress_progress_reach_height, mReachHeight); mTextOffSet = (int) ta.getDimension(R.styleable.HorizontalProgressbarWithProgress_progress_text_offset, mTextOffSet); ta.recycle(); mPaint.setTextSize(mTextSize); } @Override protected synchronized void onDraw(Canvas canvas) { /** * save:用來保存Canvas的狀態。save之後,可以調用Canvas的平移、放縮、旋轉、錯切、裁剪等操作。 */ canvas.save(); canvas.translate(getPaddingLeft(), getHeight() / 2); /** * 判斷是否需要繪制右邊的部分 */ boolean noNeedUnReach = false; /** * getProgress() 獲取當前進度 * getMax()獲取progressBar的最大進度 */ float radio = getProgress() * 1.0f / getMax(); String text = getProgress() + "%"; int textWidth = (int) mPaint.measureText(text); float progressX = radio * mRealWidth; if (progressX + textWidth > mRealWidth) { progressX = mRealWidth - textWidth; noNeedUnReach = true; } float endX = progressX - mTextOffSet / 2; if (endX > 0) { mPaint.setColor(mReachColor); mPaint.setStrokeWidth(mReachHeight); canvas.drawLine(0, 0, endX, 0, mPaint); } //draw text mPaint.setColor(mTextColor); /** * descent()是文字的底部y坐標, ascent()是文字頂部y坐標 */ int y = (int) -(mPaint.descent() + mPaint.ascent() / 2); canvas.drawText(text, progressX, y, mPaint); //draw unReach bar if (!noNeedUnReach) { float start = progressX + mTextOffSet / 2 + textWidth; mPaint.setColor(mUnReachColor); mPaint.setStrokeWidth(mUNReachHeight); canvas.drawLine(start, 0, mRealWidth, 0, mPaint); } /** * restore:用來恢復Canvas之前保存的狀態。防止save後對Canvas執行的操作對後續的繪制有影響。 * 另外,save和restore要配對使用(restore可以比save少,但不能多),如果restore調用次數比save多,會引發Error. */ canvas.restore(); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = measureHeight(heightMeasureSpec); setMeasuredDimension(width, height); /** * 上面已經通過setMeasuredDimension()確定了view的寬度和高度 * 所以可以直接通過getMeasuredWidth()獲取view的寬度 */ mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); } private int measureHeight(int heightMeasureSpec) { int result; int mode = MeasureSpec.getMode(heightMeasureSpec); int size = MeasureSpec.getSize(heightMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { /** * descent()是文字的底部y坐標, ascent()是文字頂部y坐標 * 所以兩者之差即為文字高度 */ int textHeight = (int) (mPaint.descent() - mPaint.ascent()); /** * 三者之中的最大值即為我們所繪制的view的高度. */ result = getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachHeight, mUNReachHeight), Math.abs(textHeight)); /** * 如果為wrap_content的話,則result取計算result和size的最小值 */ if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } protected int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } protected int sp2px(int sp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } }
package com.example.asiatravel.learnprogressbar.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import com.example.asiatravel.learnprogressbar.R; /** * Created by kuangxiaoguo on 16/9/8. * * 圓形進度條 */ public class RoundProgressbarWithProgress extends HorizontalProgressbarWithProgress { private int mRadius = dp2px(30); private int mMaxPaintWidth; public RoundProgressbarWithProgress(Context context) { this(context, null); } public RoundProgressbarWithProgress(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RoundProgressbarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressbarWithProgress); mRadius = (int) ta.getDimension(R.styleable.RoundProgressbarWithProgress_radius, mRadius); ta.recycle(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStrokeCap(Paint.Cap.ROUND); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); /** * 獲取最大的繪制寬度 */ mMaxPaintWidth = Math.max(mReachHeight, mUNReachHeight); //默認四個padding一致 int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight(); /** * resolveSize()方法就類似於我們自己根據MeasureSpec自己計算view的寬和高 */ int width = resolveSize(expect, widthMeasureSpec); int height = resolveSize(expect, heightMeasureSpec); int realWidth = Math.min(width, height); mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2; setMeasuredDimension(realWidth, height); } @Override protected synchronized void onDraw(Canvas canvas) { String text = getProgress() + "%"; float textWidth = mPaint.measureText(text); /** * descent()是文字的底部y坐標, ascent()是文字頂部y坐標 */ float textHeight = (mPaint.descent() + mPaint.ascent()) / 2; canvas.save(); canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2, getPaddingTop() + mMaxPaintWidth / 2); //draw unreach bar mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mUnReachColor); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); //draw reach bar mPaint.setColor(mReachColor); mPaint.setStrokeWidth(mReachHeight); float sweepAngle = getProgress() * 1.0f / getMax() * 360; canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0, sweepAngle, false, mPaint); //draw text mPaint.setColor(mTextColor); mPaint.setTextSize(mTextSize); mPaint.setStyle(Paint.Style.FILL); canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight, mPaint); canvas.restore(); } }
package com.example.asiatravel.learnprogressbar; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import com.example.asiatravel.learnprogressbar.view.HorizontalProgressbarWithProgress; import com.example.asiatravel.learnprogressbar.view.RoundProgressbarWithProgress; public class MainActivity extends AppCompatActivity { private static final int HORIZONTAL_WHAT = 0; private HorizontalProgressbarWithProgress progressBar; private RoundProgressbarWithProgress roundProgressBar; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); int progress = progressBar.getProgress(); int nextProgress = ++progress; progressBar.setProgress(nextProgress); roundProgressBar.setProgress(nextProgress); mHandler.sendEmptyMessageDelayed(HORIZONTAL_WHAT, 100); if (progress >= 100) { mHandler.removeMessages(HORIZONTAL_WHAT); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressBar = (HorizontalProgressbarWithProgress) findViewById(R.id.progressBar); roundProgressBar = (RoundProgressbarWithProgress) findViewById(R.id.round_progressBar); mHandler.sendEmptyMessage(HORIZONTAL_WHAT); } }
示例效果如下: MainActivity.xmlpackage sn.qdj.popupwindowdemo;import android.support.v7
1.一些BB上節我們把妹子圖片的數據來源從本地改成了解析Gank提供的接口數據,我們本節想對這個圖片加載類進行優化,比如加上顯示本地圖片的,另外還有一點就是緩存,我們現在
如下內容主要向廣大開發者介紹如何利用百度地圖Android SDK來構建一個最基本的地圖應用! 第一步,創建Android工程,將百度地圖Android SDK的開發包導
前置文章: 《Android 4.4 Kitkat Phone工作流程淺析(一)__概要和學習計劃》 《Android 4.4 Kitkat Phone工作