編輯:關於Android編程
如下圖:


之前寫過一個可以雙向滑動的和這個view的類似,那個滑動的view處理的onTouch事件,以及判斷了我們應該滑動哪個小球,有興趣的可以看下之前的連接
雙向滑動的SeekBarhttp://blog.csdn.net/givemeacondom/article/details/52397589
這個就比較簡單了,都是靜態的繪制,唯一的交互就是UI中的簽到按鈕,點擊一次通知自定義view繪制;
上面就是實現的思路,我們一步步看下代碼,最後會奉上源代碼的下載鏈接;
private void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SignInView, defStyleAttr, R.style.def_sign_in_style);
int indexCount = typedArray.getIndexCount();
for (int i = 0; i < indexCount; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.SignInView_sign_in_bg_clor:
signInBgColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.SignInView_sign_in_pb_clor:
signInPbColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.SignInView_sign_in_check_clor:
signInCheckColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.SignInView_sign_in_text_clor:
singInTextColor = typedArray.getColor(attr, Color.BLACK);
break;
case R.styleable.SignInView_sign_in_text_size:
singInTextSize = typedArray.getDimensionPixelSize(attr, 0);
break;
}
}
typedArray.recycle();
}
根據需求我們的這個view默認充滿屏幕,所以只需要處理height的測量模式即可
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.e("--TAG---", "onMeasure--->>");
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int measureHeight;
if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
measureHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEF_HEIGHT, getResources().getDisplayMetrics());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(measureHeight, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.e("--TAG---", "onSizeChanged--->>");
viewPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEF_PADDING, getResources().getDisplayMetrics());
int textMarginTop = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, TEXT_MARGIN_TOP, getResources().getDisplayMetrics());
// 在回調中獲取view的寬度和高度,並計算小球的半徑
viewWidth = w;
viewHeight = h;
signInBallRadio = (int) (viewHeight * SIGN_IN_BALL_SCALE / 2);
signRectHeight = (int) (signInBallRadio * SIGN_BG_RECT_SCALE);
// 矩形的背景區域,
signInBgRectF = new RectF(viewPadding + signInBallRadio, viewHeight * SECTION_SCALE - signInBallRadio - signRectHeight, viewWidth - viewPadding - signInBallRadio, viewHeight * SECTION_SCALE - signInBallRadio);
circleY = (int) (signInBgRectF.top + signRectHeight / 2);
descY = (int) (viewHeight * SECTION_SCALE) + signInBallRadio + textMarginTop;
// 核心代碼就一個方法
calculateCirclePoints(viewData);
progressRectF = signInPbRectFs.get(0);
}
private void calculateCirclePoints(List viewData) {
//獲取數據源中分開的份數,比如一周7天,中間的小段是不是有6段,所以是size-1
if (null != viewData) {
int intervalSize = viewData.size() - 1;
// 計算一份的長度,view的寬度減去兩邊的padding,以及總共小球的半徑的綜合然後除以,一共多少份
int onePiece = (viewWidth - 2 * viewPadding - signInBallRadio * 2 * viewData.size()) / intervalSize;
// 計算每個小球的坐標,x 和y,
for (int i = 0; i < viewData.size(); i++) {
// 這裡其實很簡單,就是一個小小的規律,當前的小球坐標
// 第一個小球 0個onePiece + 1個小球半徑
// 第二個小球 1個onePiece + 3個小球半徑
// 第三個小球 2個onePiece + 5個小球半徑
// ####........求第N個的距離......?是不是一個送分題
// 第N個的公式: i * onePiece + ((i + 1) * 2 - 1)*R
Point circleP = new Point(viewPadding + i * onePiece + ((i + 1) * 2 - 1) * signInBallRadio, circleY);
Point descP = new Point((int) (viewPadding + i * onePiece + ((i + 1) * 2 - 1) * signInBallRadio - signInTextPaint.measureText(viewData.get(i)) / 2), descY);
// 計算對勾的路徑
Path signInPath = new Path();
signInPath.moveTo(circleP.x - signInBallRadio / 2, circleP.y);
signInPath.lineTo(circleP.x, circleP.y + signInBallRadio / 2);
signInPath.lineTo(circleP.x + signInBallRadio / 2, circleP.y - signInBallRadio + signInBallRadio / 2);
RectF signInPbRectF = new RectF(viewPadding + signInBallRadio, viewHeight * SECTION_SCALE - signInBallRadio - signRectHeight, circleP.x, viewHeight * SECTION_SCALE - signInBallRadio);
// 保存計算的坐標;
signInPaths.add(signInPath);
circlePoints.add(circleP);
descPoints.add(descP);
signInPbRectFs.add(signInPbRectF);
}
}
}
/**
* 屬性動畫的形式繪制進度條,暫時未啟用,效果預覽可以的
*
* @param canvas
*/
private void drawSignInPbRectWithAnim(final Canvas canvas) {
if (isNeedReturn()) {
return;
}
final RectF targetRectF = signInPbRectFs.get(currentSignTag);
RectF beforeRectF;
if (currentSignTag >= 1) {
beforeRectF = signInPbRectFs.get(currentSignTag - 1);
progressRectF.left = beforeRectF.left;
}
progressRectF.right = targetRectF.right * persent;
canvas.drawRect(progressRectF, signInPbPaint);
}
// 繪制簽到進度的方法,如果想看動畫的可以自己把ondraw中的方法替換成上面的即可
private void drawSignInPbRectNoAnim(final Canvas canvas) {
if (isNeedReturn()) {
return;
}
canvas.drawRect(signInPbRectFs.get(currentSignTag), signInPbPaint);
}
private boolean isNeedReturn() {
return currentSignTag < 0 || currentSignTag >= viewData.size();
}
// 繪制選中的簽到狀態下的圓圈以及白色的對勾路徑
private void drawSingInCheckCircle(Canvas canvas) {
if (isNeedReturn()) {
return;
}
for (int i = -1; i < currentSignTag; i++) {
Point p = circlePoints.get(i + 1);
Path path = signInPaths.get(i + 1);
canvas.drawCircle(p.x, p.y, signInBallRadio, signInPbPaint);
canvas.drawPath(path, signInCheckPaint);
}
}
// 繪制簽到信息描述
private void drawSignDesc(Canvas canvas) {
for (int i = 0; i < viewData.size(); i++) {
Point p = descPoints.get(i);
canvas.drawText(viewData.get(i), p.x, p.y, signInTextPaint);
}
}
// 繪制白色的未簽到背景
private void drawSignInNormalCircle(Canvas canvas) {
for (Point p : circlePoints) {
canvas.drawCircle(p.x, p.y, signInBallRadio, signInBgPaint);
}
}
private void drawSignInBgRect(Canvas canvas) {
canvas.drawRect(signInBgRectF, signInBgPaint);
}
細說JVM系列:JVM內存空間分區
java虛擬機基本結構:JVM是一個內存中的虛擬機,那它的存儲就是內存了,我們寫的所有類、常量、變量、方法都在內存中,因此明白java虛擬機的內存分配非常重要,本部分主要
DatePicker
DatePicker實戰效果圖:依賴導入compile 'cn.aigestudio.datepicker:DatePicker:2.2.0'DatePi
Android更改EditText下劃線顏色樣式的方法
前言相信大家都知道,當使用AppCompatEditText(Edit Text)時,默認的下劃線是跟隨系統的#FF4081的顏色值的,通過改變這個值可以改變所有的顏色樣
Android多線程性能優化(一)
在程序開發中,為了讓程序表現的更快更流暢,我們會使用多線程來提升應用的並發性能。但多線程並發代碼是一個棘手的問題,線程的生命周期處理不好就會造成內存洩漏。 new