You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何在CalendarView指定日期显示红绿标记点的实现方法

Absolutely! You can totally add custom red and green markers to specific dates in CalendarView—the catch is that the default Android CalendarView doesn’t support this out of the box, so you’ll need a bit of customization. Here are two solid approaches to make this work with your existing simpleCalendarView.xml and CalendarFragment setup:

Approach 1: Customize the Native CalendarView (No Third-Party Libraries)

This method involves creating a subclass of CalendarView and overriding its drawing logic to render markers on target dates. It uses reflection to access the internal date grid, so keep in mind there might be minor compatibility quirks across Android versions.

Step 1: Create the Custom CalendarView Class

public class MarkedCalendarView extends CalendarView {
    private List<Long> redMarkDates = new ArrayList<>();
    private List<Long> greenMarkDates = new ArrayList<>();
    private Paint redPaint, greenPaint;
    private int markerRadius = 10; // Adjust this to change marker size

    public MarkedCalendarView(Context context) {
        super(context);
        initPaints();
    }

    public MarkedCalendarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initPaints();
    }

    public MarkedCalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaints();
    }

    private void initPaints() {
        // Set up red marker paint
        redPaint = new Paint();
        redPaint.setColor(Color.RED);
        redPaint.setStyle(Paint.Style.FILL);
        redPaint.setAntiAlias(true);

        // Set up green marker paint
        greenPaint = new Paint();
        greenPaint.setColor(Color.GREEN);
        greenPaint.setStyle(Paint.Style.FILL);
        greenPaint.setAntiAlias(true);
    }

    // Call this to set dates that need red markers (pass millisecond timestamps)
    public void setRedMarkDates(List<Long> dates) {
        redMarkDates.clear();
        if (dates != null) redMarkDates.addAll(dates);
        invalidate(); // Refresh the view to show new markers
    }

    // Call this to set dates that need green markers
    public void setGreenMarkDates(List<Long> dates) {
        greenMarkDates.clear();
        if (dates != null) greenMarkDates.addAll(dates);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        try {
            // Access the internal GridView that holds date cells via reflection
            Field gridField = CalendarView.class.getDeclaredField("mMonthGridView");
            gridField.setAccessible(true);
            GridView dateGrid = (GridView) gridField.get(this);
            if (dateGrid == null) return;

            Adapter dateAdapter = dateGrid.getAdapter();
            if (dateAdapter == null) return;

            // Loop through each date cell to check if it needs a marker
            for (int i = 0; i < dateAdapter.getCount(); i++) {
                View dateCell = dateAdapter.getView(i, null, dateGrid);
                if (dateCell == null) continue;

                long dateMillis = (long) dateAdapter.getItem(i);
                boolean needsRedMarker = redMarkDates.contains(dateMillis);
                boolean needsGreenMarker = greenMarkDates.contains(dateMillis);

                if (needsRedMarker || needsGreenMarker) {
                    // Calculate marker position (centered below the date text)
                    int[] cellLocation = new int[2];
                    dateCell.getLocationOnScreen(cellLocation);
                    float centerX = cellLocation[0] + dateCell.getWidth() / 2f;
                    float centerY = cellLocation[1] + dateCell.getHeight() - markerRadius - 8; // 8 = spacing from cell bottom

                    // Draw the marker
                    if (needsRedMarker) {
                        canvas.drawCircle(centerX, centerY, markerRadius, redPaint);
                    }
                    if (needsGreenMarker) {
                        canvas.drawCircle(centerX, centerY, markerRadius, greenPaint);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Step 2: Update Your Layout File

Replace the default CalendarView in simpleCalendarView.xml with your custom class (make sure to use your actual package name):

<com.your.package.name.MarkedCalendarView
    android:id="@+id/calendarView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:dateTextAppearance="@style/YourCalendarDateStyle"
    android:weekDayTextAppearance="@style/YourCalendarWeekStyle" />

Step 3: Configure Markers in CalendarFragment

public class CalendarFragment extends Fragment {
    private MarkedCalendarView calendarView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.simpleCalendarView, container, false);
        calendarView = view.findViewById(R.id.calendarView);

        // Prepare your target dates (example: add markers to specific days)
        List<Long> redMarkedDates = new ArrayList<>();
        List<Long> greenMarkedDates = new ArrayList<>();

        // Add a red marker for 2 days from today
        Calendar redDate = Calendar.getInstance();
        redDate.add(Calendar.DAY_OF_MONTH, 2);
        redMarkedDates.add(redDate.getTimeInMillis());

        // Add a green marker for 5 days from today
        Calendar greenDate = Calendar.getInstance();
        greenDate.add(Calendar.DAY_OF_MONTH, 5);
        greenMarkedDates.add(greenDate.getTimeInMillis());

        // Apply markers to the calendar
        calendarView.setRedMarkDates(redMarkedDates);
        calendarView.setGreenMarkDates(greenMarkedDates);

        // Keep your existing date click listener
        calendarView.setOnDateChangeListener((view1, year, month, dayOfMonth) -> {
            // Your existing click logic here
            Toast.makeText(getContext(), "Selected: " + year + "/" + (month+1) + "/" + dayOfMonth, Toast.LENGTH_SHORT).show();
        });

        return view;
    }
}
Approach 2: Use a Third-Party Calendar Library (Easier & More Stable)

If you want to avoid reflection and get access to more built-in features, use a library like MaterialCalendarView. It natively supports date markers via decorators.

Step 1: Add the Library Dependency

Add this to your app-level build.gradle file:

dependencies {
    implementation 'com.prolificinteractive:material-calendarview:1.4.3'
}

Step 2: Update Your Layout

Replace the default CalendarView with MaterialCalendarView:

<com.prolificinteractive.materialcalendarview.MaterialCalendarView
    android:id="@+id/materialCalendarView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Step 3: Set Up Markers in CalendarFragment

public class CalendarFragment extends Fragment {
    private MaterialCalendarView calendarView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.simpleCalendarView, container, false);
        calendarView = view.findViewById(R.id.materialCalendarView);

        // Add red and green markers using custom decorators
        calendarView.addDecorator(new DateMarkerDecorator(Color.RED, getRedMarkedDates()));
        calendarView.addDecorator(new DateMarkerDecorator(Color.GREEN, getGreenMarkedDates()));

        // Set up date click listener
        calendarView.setOnDateChangedListener((widget, date, selected) -> {
            // Your click logic here
            Toast.makeText(getContext(), "Selected: " + date.getYear() + "/" + (date.getMonth()+1) + "/" + date.getDay(), Toast.LENGTH_SHORT).show();
        });

        return view;
    }

    // Helper method to get dates for red markers
    private List<CalendarDay> getRedMarkedDates() {
        List<CalendarDay> dates = new ArrayList<>();
        dates.add(CalendarDay.from(2024, Calendar.MAY, 20)); // Example date
        return dates;
    }

    // Helper method to get dates for green markers
    private List<CalendarDay> getGreenMarkedDates() {
        List<CalendarDay> dates = new ArrayList<>();
        dates.add(CalendarDay.from(2024, Calendar.MAY, 25)); // Example date
        return dates;
    }

    // Custom decorator class to draw markers
    private static class DateMarkerDecorator implements DayViewDecorator {
        private final int markerColor;
        private final HashSet<CalendarDay> targetDates;

        public DateMarkerDecorator(int color, Collection<CalendarDay> dates) {
            this.markerColor = color;
            this.targetDates = new HashSet<>(dates);
        }

        @Override
        public boolean shouldDecorate(CalendarDay day) {
            return targetDates.contains(day);
        }

        @Override
        public void decorate(DayViewFacade view) {
            // Draw a dot below the date text (adjust radius as needed)
            view.addSpan(new DotSpan(10, markerColor));
        }
    }
}

Which Approach Should You Choose?

  • Use Approach 1 if you want to stick to native components and avoid third-party dependencies.
  • Use Approach 2 if you want a more stable, low-maintenance solution with extra features like range selection, custom date formatting, etc.

内容的提问来源于stack exchange,提问作者Sudha Kumari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:13:42