Android自定義view實現日歷打卡簽到
本文實例為大傢分享瞭Android自定義view實現日歷打卡簽到的具體代碼,供大傢參考,具體內容如下
1.說明
自己寫一個view實現每天簽到的功能,設置背景圖片
源碼下載
2.效果圖
3.主界面
package com.example.myapplication30; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.util.ArrayList; import java.util.Calendar; import java.util.List; public class MainActivity extends AppCompatActivity { //參考網址:https://blog.csdn.net/MacaoPark/article/details/102069775 private TextView mTvDaySum; private TextView mTvMonth; private SignView mCvCalendar; private List<SignEntity> data; private Calendar calendar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTvDaySum = findViewById(R.id.punch_tv_day_sum); mTvMonth = findViewById(R.id.punch_tv_month); mCvCalendar = findViewById(R.id.punch_cv_calendar); } @Override protected void onStart() { super.onStart(); onReady(); } @SuppressLint("SetTextI18n") private void onReady() { calendar = Calendar.getInstance(); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH); //int date = calendar.get(Calendar.DATE); int dayOfMonthToday = calendar.get(Calendar.DAY_OF_MONTH); List<SignDate> signDates = new ArrayList<>(); signDates.add(new SignDate(2021, 5, 1, true)); signDates.add(new SignDate(2021, 5, 2, true)); signDates.add(new SignDate(2021, 5, 3, true)); signDates.add(new SignDate(2021, 5, 4, true)); signDates.add(new SignDate(2021, 5, 5, true)); mTvDaySum.setText("本期連續登錄\t"+signDates.size()+"\t天"); mTvMonth.setText(year+"年"+getResources().getStringArray(R.array.month_array)[month]+"\t"+dayOfMonthToday+"日"); data = new ArrayList<>(); for (int i = 1; i <= dayOfMonthToday; i++) { SignEntity signEntity = new SignEntity(); if (i == dayOfMonthToday) { signEntity.setDayType(2); } else { signEntity.setDayType(1); } for (int j = 0; j < signDates.size(); j++) { if (signDates.get(j).getDay() == i) { signEntity.setDayType(0); break; } else if (dayOfMonthToday == i) { signEntity.setDayType(2); } else { signEntity.setDayType(1); } } data.add(signEntity); } SignAdapter signAdapter = new SignAdapter(data); mCvCalendar.setAdapter(signAdapter); } }
4.適配器
package com.example.myapplication30; import java.util.List; /** * SignAdapter * Created by E.M on 2016/4/21. */ public class SignAdapter extends CalendarAdapter { private List<SignEntity> data; public SignAdapter(List<SignEntity> data) { this.data = data; } @Override public SignView.DayType getType(int dayOfMonth) { return SignView.DayType.valueOf(data.get(dayOfMonth - 1).getDayType()); } }
5.自定義view
package com.example.myapplication30; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ComposeShader; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import java.util.Calendar; /** * 簽到日歷控件 * Created by E.M on 2016/4/20. */ public class SignView extends View { private static final String[] WEEK_MARK = {"一", "二", "三", "四", "五", "六", "日"}; private static final int MAX_COLUMN = 7; /** * 周內 */ private static final int COLOR_MARKER_WEEKDAY = 0xFF999999; private static final int COLOR_MARKER_WEEKEND = 0xFF1B89CD; /** * 已簽到背景色 */ //private static final int COLOR_BACKGROUND_HIGHLIGHT = 0xFFFF0000; /** * 未簽到背景色 */ private static final int COLOR_BACKGROUND_NORMAL = 0xFF9C9C9C; /** * 等待簽到背景色 */ private static final int COLOR_BACKGROUND_WAIT = 0xFFFE7471; /** * 已簽到文字顏色 */ private static final int COLOR_TEXT_HIGHLIGHT = 0xFFFFFFFF; /** * 未簽到文字顏色 */ private static final int COLOR_TEXT_NORMAL = 0xFF606060; // /** // * 不可用文字顏色 // */ // private static final int COLOR_TEXT_DISABLED = 0xFFD4D4D4; private static final int MARKER_TEXT_SIZE = 40; private static final int CELL_TEXT_SIZE = 40; private static final int VERTICAL_SPACE = 51; private static final int VERTICAL_MARGIN = 62; private static final int HORIZONTAL_MARGIN = 39; private static final int CELL_SIZE = 80; private static final int WAIT_LINE_SIZE = 14; private int dayOfMonthToday; private int markerTextY; private int verticalCellTop; private int sumDayOfMonth; private int daysOfFirstWeek; private int horizontalSpace; private int deltaTextCellY; private int deltaTextMarkerY; private int verticalSpace; private int verticalMargin; private int horizontalMargin; private int cellSize; private int waitLineSize; private Path waitPath; private Rect waitRect; private Paint paintWeekday; private Paint paintWeekend; private Paint paintTextNormal; private Paint paintTextHighlight; private Paint paintBackgroundWait; private Paint paintBackgroundNormal; private Paint paintBackgroundHighlight; private CalendarAdapter adapter; public SignView(Context context) { this(context, null); } public SignView(Context context, AttributeSet attrs) { this(context, attrs, -1); } public SignView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initResolution(); initPaint(); initData(); } private void initResolution() { // resolutionUtil = ResolutionUtil.getInstance(); // verticalSpace = resolutionUtil.formatVertical(VERTICAL_SPACE); // verticalMargin = resolutionUtil.formatVertical(VERTICAL_MARGIN); // horizontalMargin = resolutionUtil.formatHorizontal(HORIZONTAL_MARGIN); // cellSize = resolutionUtil.formatVertical(CELL_SIZE); // waitLineSize = resolutionUtil.formatVertical(WAIT_LINE_SIZE); verticalSpace = VERTICAL_SPACE; verticalMargin = VERTICAL_MARGIN; horizontalMargin = HORIZONTAL_MARGIN; cellSize = CELL_SIZE; waitLineSize = WAIT_LINE_SIZE; } private void initPaint() { // int markerTextSize = resolutionUtil.formatVertical(MARKER_TEXT_SIZE); // int cellTextSize = resolutionUtil.formatVertical(CELL_TEXT_SIZE); int markerTextSize = MARKER_TEXT_SIZE; int cellTextSize = CELL_TEXT_SIZE; paintWeekday = new Paint(); paintWeekday.setAntiAlias(true); paintWeekday.setColor(COLOR_MARKER_WEEKDAY); paintWeekday.setTextSize(markerTextSize); paintWeekday.setTextAlign(Paint.Align.CENTER); paintWeekend = new Paint(); paintWeekend.setAntiAlias(true); paintWeekend.setColor(COLOR_MARKER_WEEKEND); paintWeekend.setTextSize(markerTextSize); paintWeekend.setTextAlign(Paint.Align.CENTER); paintTextNormal = new Paint(); paintTextNormal.setAntiAlias(true); paintTextNormal.setColor(COLOR_TEXT_NORMAL); paintTextNormal.setTextSize(cellTextSize); paintTextNormal.setTextAlign(Paint.Align.CENTER); paintTextHighlight = new Paint(); paintTextHighlight.setAntiAlias(true); paintTextHighlight.setColor(COLOR_TEXT_HIGHLIGHT); paintTextHighlight.setTextSize(cellTextSize); paintTextHighlight.setTextAlign(Paint.Align.CENTER); paintBackgroundWait = new Paint(); paintBackgroundWait.setAntiAlias(true); paintBackgroundWait.setColor(COLOR_BACKGROUND_WAIT); paintBackgroundWait.setStrokeWidth(2); paintBackgroundWait.setStyle(Paint.Style.STROKE); paintBackgroundNormal = new Paint(); paintBackgroundNormal.setAntiAlias(true); paintBackgroundNormal.setColor(COLOR_BACKGROUND_NORMAL); paintBackgroundNormal.setStrokeWidth(2); paintBackgroundNormal.setStyle(Paint.Style.STROKE); paintBackgroundHighlight = new Paint(); paintBackgroundHighlight.setAntiAlias(true); paintBackgroundHighlight.setStrokeWidth(2); paintBackgroundHighlight.setStyle(Paint.Style.FILL); //顏色 //paintBackgroundHighlight.setColor(COLOR_BACKGROUND_HIGHLIGHT); //多種顏色數組 //int[] colors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW,Color.MAGENTA}; //float[] position = {0f, 0.2f, 0.4f, 0.6f, 1.0f}; //Shader shader1 = new LinearGradient(100,850,600,850,colors,position,Shader.TileMode.CLAMP); //paintBackgroundHighlight.setShader(shader1); //設置背景圖片 /* Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.small); Shader shader1 = new BitmapShader(placeholder, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); paintBackgroundHighlight.setShader(shader1);*/ } private void initData() { Paint.FontMetricsInt fmiMarker = paintWeekday.getFontMetricsInt(); deltaTextMarkerY = -(fmiMarker.bottom - fmiMarker.top) / 2 - fmiMarker.top; markerTextY = verticalMargin + cellSize / 2; Paint.FontMetricsInt fmiCell = paintTextNormal.getFontMetricsInt(); deltaTextCellY = -(fmiCell.bottom - fmiCell.top) / 2 - fmiCell.top; verticalCellTop = verticalMargin + cellSize; Calendar calendarToday = Calendar.getInstance(); dayOfMonthToday = calendarToday.get(Calendar.DAY_OF_MONTH); int dayOfWeek; sumDayOfMonth = calendarToday.getActualMaximum(Calendar.DAY_OF_MONTH); Calendar calendarFirstDay = Calendar.getInstance(); calendarFirstDay.set(Calendar.DAY_OF_MONTH, 1); dayOfWeek = calendarFirstDay.get(Calendar.DAY_OF_WEEK); if (dayOfWeek == Calendar.SUNDAY) { dayOfWeek = 7; } else { dayOfWeek = dayOfWeek - 1; } daysOfFirstWeek = MAX_COLUMN - dayOfWeek + 1; } private void createWaitBackground(int topX, int topY) { waitPath = new Path(); waitPath.moveTo(topX, topY + waitLineSize); waitPath.lineTo(topX, topY); waitPath.lineTo(topX + waitLineSize, topY); waitPath.moveTo(topX + cellSize - waitLineSize, topY + cellSize); waitPath.lineTo(topX + cellSize, topY + cellSize); waitPath.lineTo(topX + cellSize, topY + cellSize - waitLineSize); waitRect = new Rect(topX, topY, topX + cellSize, topY + cellSize); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); horizontalSpace = (w - MAX_COLUMN * cellSize - horizontalMargin * 2) / (MAX_COLUMN - 1); } @Override public void draw(Canvas canvas) { super.draw(canvas); drawWeekMark(canvas); drawCellsBackground(canvas); drawCells(canvas); } private void drawWeekMark(Canvas canvas) { int y = markerTextY + deltaTextMarkerY; for (int i = 0; i < 7; i++) { int x = horizontalMargin + i * (horizontalSpace + cellSize) + cellSize / 2; if (i < 5) { canvas.drawText(WEEK_MARK[i], x, y, paintWeekday); } else { canvas.drawText(WEEK_MARK[i], x, y, paintWeekend); } } } private void drawCellsBackground(Canvas canvas) { for (int i = 1; i <= dayOfMonthToday; i++) { drawCellBackground(canvas, i, getColumnIndex(i), getRowIndex(i)); } } /** * 根據行列序號繪制日期背景 * * @param canvas 畫佈 * @param dayOfMonth 日期 * @param column 列序號 * @param row 行序號 */ private void drawCellBackground(Canvas canvas, int dayOfMonth, int column, int row) { int x = horizontalMargin + column * (horizontalSpace + cellSize) + cellSize / 2; int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2; if (adapter != null) { DayType dayType = adapter.getType(dayOfMonth); switch (dayType) { case WAITING: if (waitPath == null) { createWaitBackground(x - cellSize / 2, y - cellSize / 2); } canvas.drawPath(waitPath, paintBackgroundWait); break; case SIGNED: // canvas.drawCircle(x, y, cellSize/2, paintBackgroundHighlight); // canvas.drawRect(x - 60, y - 60, x + 60, y + 60, paintBackgroundHighlight);// 正方形 // Bitmap placeholder = BitmapFactory.decodeResource(getResources(), R.mipmap.purtest); // canvas.drawBitmap(placeholder,);wCircle(x, y, cellSize/2, paintBackgroundHighlight); canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.small3),x-40, y-40 , paintBackgroundHighlight); break; default: canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal); break; } } else { canvas.drawCircle(x, y, cellSize / 2, paintBackgroundNormal); } } private void drawCells(Canvas canvas) { for (int i = 1; i <= sumDayOfMonth; i++) { drawCell(canvas, i, getColumnIndex(i), getRowIndex(i)); } } /** * 根據行列序號繪制日期 * * @param canvas 畫佈 * @param dayOfMonth 日期 * @param column 列序號 * @param row 行序號 */ private void drawCell(Canvas canvas, int dayOfMonth, int column, int row) { int x = horizontalMargin + column * (horizontalSpace + cellSize) + cellSize / 2; int y = verticalCellTop + verticalSpace * (row + 1) + cellSize * row + cellSize / 2 + deltaTextCellY; if (adapter != null && dayOfMonth <= dayOfMonthToday) { DayType dayType = adapter.getType(dayOfMonth); Paint paint; switch (dayType) { case SIGNED: paint = paintTextHighlight; break; default: paint = paintTextNormal; break; } canvas.drawText(String.valueOf(dayOfMonth), x, y, paint); } else { canvas.drawText(String.valueOf(dayOfMonth), x, y, paintTextNormal); } } /** * 獲取列序號 * * @param dayOfMonth 日期 * @return 列序號 */ private int getColumnIndex(int dayOfMonth) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); if (dayOfWeek == Calendar.SUNDAY) { dayOfWeek = 6; } else { dayOfWeek = dayOfWeek - 2; } return dayOfWeek; } /** * 獲取行序號 * * @param dayOfMonth 日期 * @return 行序號 */ private int getRowIndex(int dayOfMonth) { float weight = (dayOfMonth - daysOfFirstWeek) / (MAX_COLUMN * 1f); double rowIndexDouble = Math.abs(Math.ceil(weight)); return (int) rowIndexDouble; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { float x = event.getX(); float y = event.getY(); if (waitPath != null) { if (adapter.getType(dayOfMonthToday).equals(DayType.WAITING)) { if (x >= waitRect.left && y >= waitRect.top && x <= waitRect.right && y <= waitRect.bottom) { if (onTodayClickListener != null) { onTodayClickListener.onTodayClick(); } } } } } return true; } public void setAdapter(CalendarAdapter adapter) { this.adapter = adapter; this.invalidate(); } public int getDayOfMonthToday() { return dayOfMonthToday; } public void notifyDataSetChanged() { invalidate(); } private OnTodayClickListener onTodayClickListener; public void setOnTodayClickListener(OnTodayClickListener onTodayClickListener) { this.onTodayClickListener = onTodayClickListener; } public interface OnTodayClickListener { void onTodayClick(); } public enum DayType { /** * 已簽到狀態,時間已過 */ SIGNED(0), /** * 未簽到狀態,時間已過 */ UNSIGNED(1), /** * 等待狀態,即當日還未簽到 */ WAITING(2), /** * 不可達到狀態,未到時間 */ UNREACHABLE(3), /** * 不可用狀態,非當前月份 */ DISABLED(4); private int value; DayType(int value) { this.value = value; } public int getValue() { return value; } public static DayType valueOf(int value) { switch (value) { case 0: return SIGNED; case 1: return UNSIGNED; case 2: return WAITING; case 3: return UNREACHABLE; case 4: return DISABLED; default: return DISABLED; } } } }
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Android自定義模擬時鐘控件
- Android顏色處理SweepGradient掃描及梯度渲染示例
- android實現多點觸摸應用
- Android View實現圓形進度條
- Android自定義View實現柱狀波形圖的繪制