Android 自定义日历控件:实现打卡功能
Android 自定义日历控件:实现打卡功能
本文将介绍如何使用 Android 开发一个自定义日历控件,并实现简单的打卡功能。
1. 创建 CalendarView 控件
首先,创建一个名为 CalendarView 的自定义 LinearLayout 控件,并添加必要的属性和方法:
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class CalendarView extends LinearLayout {
private Context context;
private GridView gridView;
private TextView tvMonth;
private CalendarAdapter adapter;
private Calendar currentDate = Calendar.getInstance();
private SimpleDateFormat dateFormat = new SimpleDateFormat('MMMM yyyy', Locale.getDefault());
private Set<Date> markedDates = new HashSet<>();
public CalendarView(Context context) {
super(context);
this.context = context;
initialize();
}
public CalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
initialize();
}
public CalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
initialize();
}
private void initialize() {
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.calendar_view, this);
gridView = findViewById(R.id.gridview);
tvMonth = findViewById(R.id.tv_month);
findViewById(R.id.btn_prev).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
currentDate.add(Calendar.MONTH, -1);
updateCalendar();
}
});
findViewById(R.id.btn_next).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
currentDate.add(Calendar.MONTH, 1);
updateCalendar();
}
});
updateCalendar();
}
public void markDate(Date date) {
markedDates.add(date);
adapter.notifyDataSetChanged();
}
private void updateCalendar() {
List<Date> dates = getDates();
adapter = new CalendarAdapter(context, dates, currentDate);
gridView.setAdapter(adapter);
tvMonth.setText(dateFormat.format(currentDate.getTime()));
}
private List<Date> getDates() {
List<Date> dates = new ArrayList<>();
Calendar calendar = (Calendar) currentDate.clone();
calendar.set(Calendar.DAY_OF_MONTH, 1);
int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
calendar.add(Calendar.DAY_OF_MONTH, -firstDayOfWeek);
while (dates.size() < 42) {
dates.add(calendar.getTime());
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
return dates;
}
private class CalendarAdapter extends BaseAdapter {
private Context context;
private List<Date> dates;
private Calendar currentDate;
private SimpleDateFormat dateFormat = new SimpleDateFormat('dd', Locale.getDefault());
public CalendarAdapter(Context context, List<Date> dates, Calendar currentDate) {
this.context = context;
this.dates = dates;
this.currentDate = currentDate;
}
@Override
public int getCount() {
return dates.size();
}
@Override
public Object getItem(int position) {
return dates.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(context);
view = inflater.inflate(R.layout.calendar_item, parent, false);
}
TextView tvDate = view.findViewById(R.id.tv_date);
Date date = dates.get(position);
tvDate.setText(dateFormat.format(date));
if (date.getMonth() != currentDate.getTime().getMonth()) {
tvDate.setTextColor(Color.GRAY);
} else {
tvDate.setTextColor(Color.BLACK);
}
if (markedDates.contains(date)) {
tvDate.setBackgroundResource(R.drawable.circle_background); // 设置已打卡日期的背景样式
} else {
tvDate.setBackground(null); // 清除未打卡日期的背景样式
}
return view;
}
}
}
2. 创建布局文件
创建两个布局文件:
- calendar_view.xml:用于定义日历控件的整体布局
<!-- calendar_view.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_prev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Prev" />
<TextView
android:id="@+id/tv_month"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:textSize="20sp" />
<Button
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Next" />
</LinearLayout>
<GridView
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="7"
android:verticalSpacing="1dp"
android:horizontalSpacing="1dp"
android:stretchMode="columnWidth" />
</LinearLayout>
- calendar_item.xml:用于定义每个日期项的布局
<!-- calendar_item.xml -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_date"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="18sp" />
3. 在主活动中使用 CalendarView
在你的主活动中,添加以下代码来使用 CalendarView 控件并实现打卡功能:
CalendarView calendarView = findViewById(R.id.calendar_view);
calendarView.markDate(new Date()); // 标记今天为已打卡
4. 总结
通过以上步骤,你就可以创建一个带有打卡功能的自定义日历控件。你可以根据需要修改代码,例如自定义已打卡日期的样式,添加更多功能等。
注意:
- 请确保在项目的
res/drawable目录下创建名为circle_background.xml的资源文件,用于定义已打卡日期的背景样式。 - 如果你想要实现更复杂的打卡功能,例如显示打卡时间等,需要在代码中添加相应的逻辑。
原文地址: https://www.cveoy.top/t/topic/bdQa 著作权归作者所有。请勿转载和采集!