編輯:關於Android編程
如何自定義控件?
1.自定義屬性的聲明和獲取;
2.測量onMeasure;
3.布局onLayout(ViewGroup);
4.繪制onDraw;
5.onTouchEvent;
6.onInterceptTouchEvent(ViewGroup);
7.狀態的恢復與保存(與Activity生命周期有關);
自定義繪制的PrograssBar的水平進度條如下 有刻度 刻度在中間顯示

下面由代碼實現:在values文件夾下建立attr.xml 放入要繪制進度條所需要的。分別是進度條字體①顏色和②大小,Prograss走過的條的③顏色和④高度,Prograss沒有走過的條的⑤顏色和⑥高度,還有顯示數值和進度條之間有間隔的空間⑦寬度。一共七個參數。
新建包View,並新建類class horizonalPrograssBarWithPrograss,如下:
package com.chase.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.chase.cn.customprograssbar.R;
/**
* Created by Chase on 2016/11/29.
*/
public class horizonalPrograssBarWithPrograss extends ProgressBar {
//這裡聲明默認值
private static final int DEFAULT_TEXT_SIZE = 10;//sp
private static final int DEFAULT_TEXT_COLOR = 0xFFC00D1;
private static final int DEFAULT_COLOR_UNREACH = 0XFFD3D6DA;
private static final int DEFAULT_HEIGHT_UNREACH = 2;//dp
private static final int DEFAULT_COLOR_REACH = 0xFFC00D1;
private static final int DEFAULT_HRIGHT_REACH = 2;//dp
private static final int DEFAULT_TEXT_OFFSET = 10;//dp
//編寫我們的值
private int mTextSize = dp2px(DEFAULT_TEXT_SIZE);
private int mTextColor = DEFAULT_TEXT_COLOR;
private int mUnReachColor = DEFAULT_COLOR_UNREACH;
private int mUnReachHeight = DEFAULT_HEIGHT_UNREACH;
private int mReachColor = DEFAULT_COLOR_REACH;
private int mReachHeight = DEFAULT_HRIGHT_REACH;
private int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);
private Paint mPaint = new Paint();
private int mRealWidth; //進度條實際寬度
//2個參數法
public horizonalPrograssBarWithPrograss(Context context, AttributeSet attrs) {
this(context, attrs, 0);//2個參數繼承3個參數的方法
}
public horizonalPrograssBarWithPrograss(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainStyledAttrs(attrs);
}
//獲取自定義屬性
private void obtainStyledAttrs(AttributeSet attrs) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.horizonalPrograssBarWithPrograss);
mTextSize = (int) ta.getDimension(R.styleable.horizonalPrograssBarWithPrograss_text_size, mTextSize);
mTextColor = ta.getColor(R.styleable.horizonalPrograssBarWithPrograss_text_color, mTextColor);
mTextOffset = (int) ta.getDimension(R.styleable.horizonalPrograssBarWithPrograss_prograss_text_offset, mTextOffset);
mUnReachColor = ta.getColor(R.styleable.horizonalPrograssBarWithPrograss_prograss_unreach_color, mUnReachColor);
mUnReachHeight = (int) ta.getDimension(R.styleable.horizonalPrograssBarWithPrograss_prograss_unreach_height, mUnReachHeight);
mReachColor = ta.getColor(R.styleable.horizonalPrograssBarWithPrograss_prograss_reach_color, mReachColor);
mReachHeight = (int) ta.getDimension(R.styleable.horizonalPrograssBarWithPrograss_prograss_reach_height, mReachHeight);
mPaint.setTextSize(mTextSize);
ta.recycle();
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// int widthMode = MeasureSpec.getMode(widthMeasureSpec);//因為是水平進度條 默認寬度為用戶的輸入 所以不需要判斷
int widthVal = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(widthVal, height);//完成測量
//實際繪制區域的寬度
mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
}
//高度測量的方法
private int measureHeight(int heightMeasureSpec) {
int result = 0;
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {//精確值,用戶給的精確值 如200dp marchparent
result = size;
} else {//否則寬度 是由文字的距離確定的
int textHeight = (int) (mPaint.descent() - mPaint.ascent());
result = getPaddingTop() //上邊距
+ getPaddingBottom() //下邊距
+ Math.max(Math.max(mReachHeight, mUnReachHeight), Math.abs(textHeight));//三者最大值
if (mode == MeasureSpec.AT_MOST) {
result = Math.min(result, size);
}
}
return result;
}
//1個參法
public horizonalPrograssBarWithPrograss(Context context) {
this(context, null);//繼承兩個參數的構造方法,當用戶在使用時new的時候用,但是使用時一般是用兩個參數的構造方法的
}
/**
*
下面是繪制進度條的方法
* @param canvas
*/
@Override
protected synchronized void onDraw(Canvas canvas) {
// super.onDraw(canvas);
canvas.save();
canvas.translate(getPaddingLeft(), getHeight() / 2);//移動畫布到 最左邊 正中間
//判斷是否需要繪制unReachBar
boolean noNeedUnReach = false;
//DrawReachBar如下:
//拿到文本寬度
String text = getProgress() + "";
int textWidth = (int) mPaint.measureText(text);
float ratio = getProgress() * 1.0f / getMax();
float prograssX = ratio * mRealWidth;
if (prograssX + textWidth > mRealWidth) {
prograssX = mRealWidth - textWidth;//防止進度條到100文本出去
noNeedUnReach = true;
}
float endX = prograssX - mTextOffset / 2;
if (endX > 0) {
mPaint.setColor(mReachColor);
mPaint.setStrokeWidth(mReachHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
//Draw Text
mPaint.setColor(mTextColor);
int y = (int) (-(mPaint.descent()+mPaint.ascent())/2);
canvas.drawText(text,prograssX,y,mPaint);
//Draw UnReachBar
if (!noNeedUnReach){
float start = prograssX + mTextOffset/2 +textWidth;
mPaint.setColor(mUnReachColor);
mPaint.setStrokeWidth(mReachHeight);
canvas.drawLine(start,0,mRealWidth,0,mPaint);
}
canvas.restore();
}
//轉換方法dp 2 px
private int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}
private int sp2px(int spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, getResources().getDisplayMetrics());
}
}
這是進度條的繪制完成了,上面進度條高度的測量,實際比較關鍵的是測量文字的高度,如圖:
然後現在可以在activity_main.xml中定義並測試:
就如上面的,我們可以自定義進度條的屬性,只需要添加這行:(這是在AS中)
xmlns:chase="http://schemas.android.com/apk/res-auto"
Eclipse中應該要這麼寫(跟上ManiFeast中顯示的包名):
xmlns:chase="http://schemas.android.com/apk/com.chase.cn.customprograssbar"
如前面所示,第二個PrograssBar進行進度變化測試,在MainActivity中:用handler進行測試:
package com.chase.cn.customprograssbar;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import com.chase.view.horizonalPrograssBarWithPrograss;
public class MainActivity extends AppCompatActivity {
private horizonalPrograssBarWithPrograss mPrograss;
private static final int MSG_UPDATE = 0x111;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
int prograss = mPrograss.getProgress();
mPrograss.setProgress(++prograss);
if (prograss>=100){
handler.removeMessages(MSG_UPDATE);
}else {
handler.sendEmptyMessageDelayed(MSG_UPDATE,100);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPrograss = (horizonalPrograssBarWithPrograss) findViewById(R.id.prograss2);
handler.sendEmptyMessage(MSG_UPDATE);
}
}
Android UI設計系列之自定義TextView屬性實現帶下劃線的文本框(4)
在Android開發過程中,如果Android系統自帶的屬性不能滿足我們日常開發的需求,那麼就需要我們給系統控件添加額外的屬性了。假如有個需求是實現帶下劃線的文本顯示(下
Android RecyclerView使用詳解
簡介RecyclerView是Google在android-supportv7包中推出的一個新的控件,該控件的主要作用是用於替代ListView、GridView,相比較
Android 活動的生命周期
1.返回棧Android 是使用任務(Task)來管理活動的,一個任務就是一組存放在棧裡的活動的集合,這個棧也被稱作返回棧(Back Stack)。棧是一種後進先出的數據
Android 圖片三級緩存加載框架原理解析與代碼實現
本文主要介紹三級緩存的原理解析與實現方式。以前一直覺得三級緩存圖片加載是一個很難理解的東西,但是自己看了一下午再試著寫了一遍之後感覺還是只要沉下心思考還時很容易熟悉掌握的