胜多负少

This commit is contained in:
coco
2026-07-15 18:28:01 +08:00
parent 7846a45f2c
commit 6d273b9854
233 changed files with 27258 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
# Built application files
*.apk
*.ap_
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
.idea/workspace.xml
# Keystore files
*.jks
Binary file not shown.
Binary file not shown.
+137
View File
@@ -0,0 +1,137 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<DBN-PSQL>
<case-options enabled="false">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false" />
</DBN-PSQL>
<DBN-SQL>
<case-options enabled="false">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false">
<option name="STATEMENT_SPACING" value="one_line" />
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
</formatting-settings>
</DBN-SQL>
<codeStyleSettings language="XML">
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<compositeConfiguration>
<compositeBuild compositeDefinitionSource="SCRIPT" />
</compositeConfiguration>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/calendarview" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="testRunner" value="PLATFORM" />
</GradleProjectSettings>
</option>
</component>
</project>
+39
View File
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
<option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
</project>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/CalendarViewProject.iml" filepath="$PROJECT_DIR$/CalendarViewProject.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/calendarview/calendarview.iml" filepath="$PROJECT_DIR$/calendarview/calendarview.iml" />
</modules>
</component>
</project>
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+403
View File
@@ -0,0 +1,403 @@
# CalendarView doc
### **CalendarView** Characteristics
- Based on Canvas, Extreme speed
- Hot plug UI customization
- Support month view、 week view、year view、lunar calendar and so on
- Support static or dynamic setting of week start
- Support for static or dynamic setting of calendar item height
- Support date interceptor and range
- Support multi-touch, smooth scrolling calendar
- Support like NestedScrolling
- All UI depends on your drawing
### 1、Create a class extends the **MonthView** or **RangeMonthView**、**MultiMonthView**.
### If you need WeekView, also create a class extends the **WeekView** or **RangeWeekView**、**MultiWeekView**.
- Implement these three methods **onDrawSelected** **onDrawScheme** **onDrawText**, like this
```java
/**
* CustomMonthView with canvas
*/
public class CustomMonthView extends MonthView {
/**
* draw select calendar
*
* @param canvas canvas
* @param calendar select calendar
* @param x calendar item x start point
* @param y calendar item y start point
* @param hasScheme is calendar has scheme?
* @return if return true will call onDrawScheme again
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
canvas.drawRect(x , y , x + mItemWidth , y + mItemHeight, mSelectedPaint);
return true;
}
/**
* draw scheme if calendar has scheme
*
* @param canvas canvas
* @param calendar calendar has scheme
* @param x calendar item x start point
* @param y calendar item y start point
*/
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
canvas.drawCircle(x + mItemWidth / 2, y + mItemHeight - 3 * mPadding, mPointRadius, mPointPaint);
}
/**
* draw text
*
* @param canvas canvas
* @param calendar calendar
* @param x calendar item x start point
* @param y calendar item y start point
* @param hasScheme is calendar has scheme?
* @param isSelected is calendar selected?
*/
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine + y;
int cx = x + mItemWidth / 2;
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
}
}
```
- Add the class path in xml
```xml
<attr name="month_view" format="string" /><!--you MonthView.class path-->
<attr name="week_view" format="string" /> <!--you WeekView.class path-->
<com.haibin.calendarview.CalendarView
android:id="@+id/calendarView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:month_view="com.haibin.calendarviewproject.meizu.MeiZuMonthView"
app:week_view="com.haibin.calendarviewproject.meizu.MeizuWeekView" />
```
- You can also use the hot plug feature, Quickly switch UI styles
```java
mCalendarView.setWeekView(MeiZuWeekView.class);
mCalendarView.setMonthView(MeiZuMonthView.class);
```
- Calendar has multiple view modes to choose depending on your needs
```xml
MonthView、WeekViewand select_mode="default_mode"
Same as mobile phone calendar,date interceptor is not supported
```
```xml
MonthView、WeekViewand select_mode="single_mode"
Single mode, support date interceptor
```
```xml
RangeMonthView、RangeWeekViewneed set select_mode="range_mode"
support date intercept
```
```xml
MultiMonthView、MultiWeekViewneed set select_mode="multi_mode"
support date intercept
```
- If you need WeekViewAdd parent layout **CalendarLayout** in **CalendarView**
```xml
<com.haibin.calendarview.CalendarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:default_status="shrink"
app:calendar_content_view_id="@+id/recyclerView">
<com.haibin.calendarview.CalendarView
android:id="@+id/calendarView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:month_view="com.haibin.calendarviewproject.simple.SimpleMonthView"
app:week_view="com.haibin.calendarviewproject.simple.SimpleWeekView"
app:week_bar_view="com.haibin.calendarviewproject.EnglishWeekBar"
app:month_view_show_mode="mode_only_current" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" />
</com.haibin.calendarview.CalendarLayout>
```
- You can use the listener to monitor the WeekView and MonthView switch
```java
public void setOnViewChangeListener(OnViewChangeListener listener);
```
- All off **CalendarLayout** attrSmooth scrolling calendar. If used **CalendarLayout**you need set **calendar_content_view_id**
```xml
<attr name="default_status">
<enum name="expand" value="0" />
<enum name="shrink" value="1" />
</attr>
<!-- gesture -->
<attr name="gesture_mode">
<enum name="default_mode" value="0" />
<enum name="disabled" value="2" />
</attr>
<attr name="calendar_show_mode">
<enum name="both_month_week_view" value="0" />
<enum name="only_week_view" value="1" />
<enum name="only_month_view" value="2" />
</attr>
<attr name="calendar_content_view_id" format="integer" />
```
- If you need a full style **CalendarView**, make app:calendar_match_parent="true", No need to use CalendarLayout
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/full_calendar.png" width="400"/>
- The **CalendarView** also provides a YearView if you need it
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/year_view.png" width="400"/>
- If you need to quick jump date
```
CalendarView.scrollToCalendar();
CalendarView.scrollToNext();
CalendarView.scrollToPre();
CalendarView.scrollToXXX();
```
- Support static or dynamic setting of week start
```
app:week_start_with="mon、sun、sat"
mCalendarView.setWeekStarWithSun();
mCalendarView.setWeekStarWithMon();
mCalendarView.setWeekStarWithSat();
```
- Set calendar range
```
<attr name="min_year" format="integer" />
<attr name="max_year" format="integer" />
<attr name="min_year_month" format="integer" />
<attr name="max_year_month" format="integer" />
<attr name="min_year_day" format="integer" />
<attr name="max_year_day" format="integer" />
CalendarView.setRange(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay)
```
- Add OnCalendarInterceptListener to intercept calendar
```java
mCalendarView.setOnCalendarInterceptListener(new CalendarView.OnCalendarInterceptListener() {
@Override
public boolean onCalendarIntercept(Calendar calendar) {
return calendar.isWeekend();
}
@Override
public void onCalendarInterceptClick(Calendar calendar, boolean isClick) {
//todo 点击拦截的日期回调
}
});
```
- You can get interception and range results in month and week view
```java
boolean isInRange = isInRange(calendar);
boolean isEnable = !onCalendarIntercept(calendar);
```
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/range.png" height="650"/>
- The **CalendarView** provides scheme setting, **setSchemeDate(Map<String, Calendar> mSchemeDates)**
- class **Calendar**
```java
boolean isWeekend();
int getWeek();
String getSolarTerm();
String getGregorianFestival();
String getTraditionFestival();
boolean isLeapYear();
int getLeapMonth();
boolean isSameMonth(Calendar calendar);
int compareTo(Calendar calendar);
long getTimeInMillis();
int differ(Calendar calendar);
```
### All of **CalendarView** attr
```xml
<declare-styleable name="CalendarView">
<attr name="calendar_padding" format="dimension" /><!--CalendarView left and right padding-->
<attr name="month_view" format="color" /> <!--Custom class path-->
<attr name="week_view" format="string" /> <!--Custom class path-->
<attr name="week_bar_height" format="dimension" /> <!--WeekBar height-->
<attr name="week_bar_view" format="string" /> <!--Custom WeekBar class path -->
<attr name="week_line_margin" format="dimension" /><!--line margin-->
<attr name="week_line_background" format="color" /><!--line color-->
<attr name="week_background" format="color" /> <!--WeekBar background-->
<attr name="week_text_color" format="color" /> <!--WeekBar text color-->
<attr name="week_text_size" format="dimension" /><!--WeekBar text size-->
<attr name="current_day_text_color" format="color" /> <!--current day text color-->
<attr name="current_day_lunar_text_color" format="color" /><!--current day lunar text color-->
       <attr name="calendar_height" format="string" /> <!--calendar item height-->
<attr name="day_text_size" format="string" /> <!--calendar day text size-->
<attr name="lunar_text_size" format="string" /> <!--calendar lunar text size-->
<attr name="scheme_text_color" format="color" /> <!--calendar scheme text color-->
<attr name="scheme_month_text_color" format="color" /> <!--calendar has scheme month text color-->
<attr name="scheme_lunar_text_color" format="color" /> <!--calendar has scheme lunar text color-->
<attr name="scheme_theme_color" format="color" /> <!-- calendar scheme background theme color-->
<attr name="selected_theme_color" format="color" /> <!--selected calendar theme color-->
<attr name="selected_text_color" format="color" /> <!--selected calendar text color-->
<attr name="selected_lunar_text_color" format="color" /> <!--selected calendar lunar text color-->
<attr name="current_month_text_color" format="color" /> <!--current month text color-->
<attr name="other_month_text_color" format="color" /> <!--other month text color-->
<attr name="current_month_lunar_text_color" format="color" /> <!--current month lunar text color-->
<attr name="other_month_lunar_text_color" format="color" /> <!--other month lunar text color-->
<!-- YearView -->
<attr name="year_view_month_text_size" format="dimension" /> <!-- year view month text size -->
<attr name="year_view_day_text_size" format="dimension" /> <!-- year_view_day_text_size -->
<attr name="year_view_month_text_color" format="color" /> <!-- year_view_month_text_color -->
<attr name="year_view_day_text_color" format="color" /> <!-- year_view_day_text_color -->
<attr name="year_view_scheme_color" format="color" /> <!-- year_view_scheme_color -->
<attr name="min_year" format="integer" />  <!--min_year-->
 <attr name="max_year" format="integer" /> <!--max_year-->
<attr name="min_year_month" format="integer" /> <!--min_year_month-->
<attr name="max_year_month" format="integer" /> <!--max_year_month-->
<!--MonthView can scrollable-->
<attr name="month_view_scrollable" format="boolean" />
<!--WeekView can scrollable-->
<attr name="week_view_scrollable" format="boolean" />
<!--YearView can scrollable-->
<attr name="year_view_scrollable" format="boolean" />
       
<!--MonthView show mode-->
<attr name="month_view_show_mode">
<enum name="mode_all" value="0" /> <!--show pre cur next month calendar-->
<enum name="mode_only_current" value="1" /> <!--show only current month-->
<enum name="mode_fix" value="2" /> <!--fix current month-->
</attr>
<!-- WeekStar -->
<attr name="week_start_with">
<enum name="sun" value="1" />
<enum name="mon" value="2" />
<enum name="sat" value="7" />
</attr>
<!-- select_mode -->
<attr name="select_mode">
<enum name="default_mode" value="0" />
<enum name="single_mode" value="1" />
<enum name="range_mode" value="2" />
<enum name="multi_mode" value="3" />
</attr>
<!-- when select_mode = multi_mode -->
<attr name="max_multi_select_size" format="integer" />
<!-- when select_mode=range_mode -->
<attr name="min_select_range" format="integer" />
<attr name="max_select_range" format="integer" />
<!-- auto select day -->
<attr name="month_view_auto_select_day">
<enum name="first_day_of_month" value="0" />
<enum name="last_select_day" value="1" />
<enum name="last_select_day_ignore_current" value="2" />
</attr>
</declare-styleable>
```
### Better use with Demo when using.The calendar is very simple to customize
+428
View File
@@ -0,0 +1,428 @@
# CalendarView使用详细文档
### 日历控件定制是移动开发平台上比较常见的而且比较难的需求,一般会遇到以下问题:
- **性能差,加载速度慢**,原因是各种基于GridView或RecyclerView等ViewGroup实现的日历,控件数太多,假设一个月视图界面有42个item,每个item里面分别就有2个子TextView:天数、农历数和本身3个控件,这样一个月视图就有42 \* 3+1RecyclerView or GridView),清楚ViewPager特性的开发者就会明白,一般ViewPager持有3个item,那么一个日历控件持有的View控件数的数量将达到 1ViewPager+ 3(RecyclerView or GridView) + 3 \* 42 \* 3 = **382**,如果用1个View来代替RecyclerView等,用Canvas来代替各种TextView,那View的数量瞬间将下降360+,内存和性能优势将相当明显了
- **难定制** 一般日历框架发布的同时也将UI风格确定下来了,假如人人都使用这个日历框架,那么将会千篇一律,难以突出自己的风格,要么就得改源码,成本太大,不太实际
- **功能性不足** 例如无法自定义周起始、无法更改选择模式、动态设置UI等等
- **无法满足产品经理提出的变态需求** 今天产品经历说我们要这样的实现、明天跟你说这里得改、后天说我们得限制一些日期...
### 但现在有了全新的 **CalendarView** 控件,它解锁了各种姿势,而且你可以任意定制,直到你满足为止...
### 插拔式设计
插拔式设计:好比插座一样,插上灯泡就会亮,插上风扇就会转,看用户需求什么而不是看插座有什么,只要是电器即可。此框架使用插拔式,既可以在编译时指定年月日视图,如:app:month_view="xxx.xxx.MonthView.class",也可在运行时动态更换年月日视图,如:CalendarView.setMonthViewClass(MonthView.Class),从而达到UI即插即用的效果,相当于框架不提供UI实现,让UI都由客户端实现,不至于日历UI都千篇一律,只需遵守插拔式接口即可随意定制,自由化程度非常高。
### **CalendarView** 的特性
- 基于Canvas绘制,极速性能
- 热插拔思想,任意定制周视图、月视图,即插即用!
- 支持单选、多选、范围选择、国内手机日历默认自动选择等选择模式
- 支持静态、动态设置周起始,一行代码搞定
- 支持静态、动态设置日历项高度、日历填充模式
- 支持设置任意日期范围、任意拦截日期
- 支持多点触控、手指平滑切换过渡,拒绝界面抖动
- 类NestedScrolling特性,嵌套滚动
- 既然这么多支持,那一定支持英语、繁体、简体,任意定制实现
### **注意:** 框架本身只是实现各自逻辑,不实现UI,UI如同一张白纸,任凭客户端自行通过Canvas绘制实现,如果不熟悉Canvas的,请自行了解各自Canvas.drawXXX方法,UI都靠Canvas实现,坐标都已经计算好了,因此怎么隐藏农历,怎么换某些日期的字,这些都不属于框架范畴,只要你想换,都能随便换。
### **再次注意:** app Demo只是Demo,只是示例如何使用,与框架本身没有关联,不属于框架一部分
### 接下来请看**CalendarView**操作,前方高能
- 你这样继承自己的月视图和周视图,只需要依次实现绘制选中:**onDrawSelected**、绘制事务:**onDrawScheme**、绘制文本:**onDrawText** 这三个回调即可,参数和坐标都已经在回调函数上实现好,周视图也是一样的逻辑,只是不需要y参数
```java
/**
* 定制高仿魅族日历界面,按你的想象力绘制出各种各样的界面
*
*/
public class MeiZuMonthView extends MonthView {
/**
* 绘制选中的日子
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return 返回true 则绘制onDrawScheme,因为这里背景色不是是互斥的,所以返回true
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
//这里绘制选中的日子样式,看需求需不需要继续调用onDrawScheme
return true;
}
/**
* 绘制标记的事件日子
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
//这里绘制标记的日期样式,想怎么操作就怎么操作
}
/**
* 绘制文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
//这里绘制文本,不要再问我怎么隐藏农历了,不要再问我怎么把某个日期换成特殊字符串了,要怎么显示你就在这里怎么画,你不画就不显示,是看你想怎么显示日历的,而不是看框架
}
}
```
- 当你实现好之后,直接在xml界面上添加特性,编译后可以即时预览效果:
```xml
<attr name="month_view" format="string" /><!--自定义月视图路径-->
<attr name="week_view" format="string" /> <!--自定义周视图路径-->
app:month_view="com.haibin.calendarviewproject.MeiZuMonthView"
app:week_view="com.haibin.calendarviewproject.MeiZuWeekView"
```
- 视图有多种模式可供选择,几乎涵盖了各种需求,看各自的需求自行继承
```xml
如果继承这2个,MonthView、WeekView,即select_mode="default_mode",这是默认的手机自带的日历模式,会自动选择月的第一天,不支持拦截器,
也可以设置select_mode="single_mode",即单选模式,支持拦截器
如果继承这2个,RangeMonthView、RangeWeekView,即select_mode="range_mode",这是范围选择模式,支持拦截器
如果继承这2个,MultiMonthView、MultiWeekView,即select_mode="multi_mode",这是多选模式,支持拦截器
```
- 如果静态模式无法满足你的需求,你可能需要动态变换定制的视图界面,你可以使用热插拔特性,即插即用,不爽就换:
```java
mCalendarView.setWeekView(MeiZuWeekView.class);
mCalendarView.setMonthView(MeiZuMonthView.class);
```
- 如果你需要可收缩的日历,你可以在 **CalendarView** 父布局添加 **CalendarLayout**,当然你不需要周视图也可以不用,例如原生日历,使用如下:
```xml
<com.haibin.calendarview.CalendarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:default_status="shrink"
app:calendar_show_mode="only_week_view"
app:calendar_content_view_id="@+id/recyclerView">
<com.haibin.calendarview.CalendarView
android:id="@+id/calendarView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
app:month_view="com.haibin.calendarviewproject.simple.SimpleMonthView"
app:week_view="com.haibin.calendarviewproject.simple.SimpleWeekView"
app:week_bar_view="com.haibin.calendarviewproject.EnglishWeekBar"
app:calendar_height="50dp"
app:current_month_text_color="#333333"
app:current_month_lunar_text_color="#CFCFCF"
app:min_year="2004"
app:other_month_text_color="#e1e1e1"
app:scheme_text="假"
app:scheme_text_color="#333"
app:scheme_theme_color="#333"
app:selected_text_color="#fff"
app:selected_theme_color="#333"
app:week_start_with="mon"
app:week_background="#fff"
app:month_view_show_mode="mode_only_current"
app:week_text_color="#111" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" />
</com.haibin.calendarview.CalendarLayout>
```
- 使用可收缩的日历你可以使用监听器,监听视图变换
```java
public void setOnViewChangeListener(OnViewChangeListener listener);
```
- 当然 **CalendarLayout** 有很多特性可提供周月视图无缝切换,而且,平滑手势不抖动!使用 **CalendarLayout**,你需要指定 **calendar_content_view_id**,用他来平移收缩月视图,更多特性如下:
```xml
<!-- 日历显示模式 -->
<attr name="calendar_show_mode">
<enum name="both_month_week_view" value="0" /><!-- 默认都有 -->
<enum name="only_week_view" value="1" /><!-- 仅周视图 -->
<enum name="only_month_view" value="2" /><!-- 仅月视图 -->
</attr>
<attr name="default_status">
<enum name="expand" value="0" /> <!--默认展开-->
<enum name="shrink" value="1" /><!--默认搜索-->
</attr>
<attr name="calendar_content_view_id" format="integer" /><!--内容布局id,用于提供月视图平移过渡-->
```
- **CalendarView** 可以设置全屏,只需设置 app:calendar_match_parent="true"即可,全屏**CalendarView**是不需要周视图的,不必嵌套CalendarLayout
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/full_calendar.png" width="400"/>
- **CalendarView** 也提供了高效便利的年视图,可以快速切换年份、月份,十分便利
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/year_view.png" width="400"/>
- 但年视图也不一定就适合你的胃口,如果你希望像弹出 **DatePickerView**,通过它来跳转日期,你可以使用以下的API来让日历与其它控件联动
```
CalendarView.scrollToCalendar();
CalendarView.scrollToNext();
CalendarView.scrollToPre();
CalendarView.scrollToXXX();
```
- 你也许需要像魅族日历一样,可以静态、动态更换周起始
```
app:week_start_with="mon、sun、sat"
CalendarView.setWeekStarWithSun();
CalendarView.setWeekStarWithMon();
CalendarView.setWeekStarWithSat();
```
- 假如你是做酒店、旅游等应用场景的APP的,那么需要可选范围的日历,你可以这样继承,和普通视图实现完全一样
```java
public class CustomRangeMonthView extends RangeMonthView{
}
public class CustomRangeWeekView extends RangeWeekView{
}
```
- 然后你需要设置选择模式为范围模式:**select\_mode="range\_mode"**
- 酒店式日历场景当然是不能从昨天开始订房的,也不能无限期订房,所以你需要静态或动态设置日历范围、精确到具体某一天!!!
```
<attr name="min_year" format="integer" />
<attr name="max_year" format="integer" />
<attr name="min_year_month" format="integer" />
<attr name="max_year_month" format="integer" />
<attr name="min_year_day" format="integer" />
<attr name="max_year_day" format="integer" />
CalendarView.setRange(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay)
```
- 当然还有更特殊的日子也是不能选择的,例如:某月某号起这N天时间内因为超强台风来袭,酒店需停止营业N天,这段期间不可订房,这时日期拦截器就排上用场了
```java
//设置日期拦截事件
mCalendarView.setOnCalendarInterceptListener(new CalendarView.OnCalendarInterceptListener() {
@Override
public boolean onCalendarIntercept(Calendar calendar) {
//这里写拦截条件,返回true代表拦截,尽量以最高效的代码执行
return calendar.isWeekend();
}
@Override
public void onCalendarInterceptClick(Calendar calendar, boolean isClick) {
//todo 点击拦截的日期回调
}
});
```
- 添加日期拦截器和范围设置后,你可以在周月视图按需求获得他们的结果
```java
boolean isInRange = isInRange(calendar);//日期是否在范围内,超出范围的可以置灰
boolean isEnable = !onCalendarIntercept(calendar);//日期是否可用,没有被拦截,被拦截的可以置灰
```
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/range.png" height="650"/>
- 假如你是做清单类、任务类APP的,可能会有这样的需求:标记某天事务的进度,这也很简单,因为:日历界面长什么样,你自己说了算!!!
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/progress_expand.png" width="400"/>
- 也许你只需要像原生日历那样就够了,但原生日历那奇怪且十分不友好的style,受到theme的影响,各种头疼,使用此控件,你只需要简简单单定制月视图就够了,**CalendarView** 能非常简单就高仿各种日历UI
- **CalendarView** 提供了 **setSchemeDate(Map<String, Calendar> mSchemeDates)** 这个十分高效的API用来动态标记事务,即时你的数据量达到数千、数万、数十万,都不会对UI渲染造成影响
- 日历类 **Calendar** 提供了许多十分有用的API
```java
boolean isWeekend();//判断是不是周末,可以用不同的画笔绘制周末的样式
int getWeek();//获取星期
String getSolarTerm();//获取24节气,可以用不同颜色标记不同节日
String getGregorianFestival();//获取公历节日,自由判断,把节日换上喜欢的颜色
String getTraditionFestival();//获取传统节日
boolean isLeapYear();//是否是闰年
int getLeapMonth();//获取闰月
boolean isSameMonth(Calendar calendar);//是否相同月
int compareTo(Calendar calendar);//比较日期大小 -1 0 1
long getTimeInMillis();//获取时间戳
int differ(Calendar calendar);//日期运算,相差多少天
```
### **CalendarView** 的全部xml特性如下:
```xml
<declare-styleable name="CalendarView">
<attr name="calendar_padding" format="dimension" /><!--日历内部左右padding-->
<attr name="month_view" format="color" /> <!--自定义类日历月视图路径-->
<attr name="week_view" format="string" /> <!--自定义类周视图路径-->
<attr name="week_bar_height" format="dimension" /> <!--星期栏的高度-->
<attr name="week_bar_view" format="color" /> <!--自定义类周栏路径,通过自定义则 week_text_color week_background xml设置无效,当仍可java api设置-->
<attr name="week_line_margin" format="dimension" /><!--线条margin-->
<attr name="week_line_background" format="color" /><!--线条颜色-->
<attr name="week_background" format="color" /> <!--星期栏的背景-->
<attr name="week_text_color" format="color" /> <!--星期栏文本颜色-->
<attr name="week_text_size" format="dimension" /><!--星期栏文本大小-->
<attr name="current_day_text_color" format="color" /> <!--今天的文本颜色-->
<attr name="current_day_lunar_text_color" format="color" /><!--今天的农历文本颜色-->
       <attr name="calendar_height" format="string" /> <!--日历每项的高度,56dp-->
<attr name="day_text_size" format="string" /> <!--天数文本大小-->
<attr name="lunar_text_size" format="string" /> <!--农历文本大小-->
<attr name="scheme_text" format="string" /> <!--标记文本-->
<attr name="scheme_text_color" format="color" /> <!--标记文本颜色-->
<attr name="scheme_month_text_color" format="color" /> <!--标记天数文本颜色-->
<attr name="scheme_lunar_text_color" format="color" /> <!--标记农历文本颜色-->
<attr name="scheme_theme_color" format="color" /> <!--标记的颜色-->
<attr name="selected_theme_color" format="color" /> <!--选中颜色-->
<attr name="selected_text_color" format="color" /> <!--选中文本颜色-->
<attr name="selected_lunar_text_color" format="color" /> <!--选中农历文本颜色-->
<attr name="current_month_text_color" format="color" /> <!--当前月份的字体颜色-->
<attr name="other_month_text_color" format="color" /> <!--其它月份的字体颜色-->
<attr name="current_month_lunar_text_color" format="color" /> <!--当前月份农历节假日颜色-->
<attr name="other_month_lunar_text_color" format="color" /> <!--其它月份农历节假日颜色-->
<!-- 年视图相关 -->
<attr name="year_view_month_text_size" format="dimension" /> <!-- 年视图月份字体大小 -->
<attr name="year_view_day_text_size" format="dimension" /> <!-- 年视图月份日期字体大小 -->
<attr name="year_view_month_text_color" format="color" /> <!-- 年视图月份字体颜色 -->
<attr name="year_view_day_text_color" format="color" /> <!-- 年视图日期字体颜色 -->
<attr name="year_view_scheme_color" format="color" /> <!-- 年视图标记颜色 -->
<attr name="min_year" format="integer" />  <!--最小年份1900-->
 <attr name="max_year" format="integer" /> <!--最大年份2099-->
<attr name="min_year_month" format="integer" /> <!--最小年份对应月份-->
<attr name="max_year_month" format="integer" /> <!--最大年份对应月份-->
<!--月视图是否可滚动-->
<attr name="month_view_scrollable" format="boolean" />
<!--周视图是否可滚动-->
<attr name="week_view_scrollable" format="boolean" />
<!--年视图是否可滚动-->
<attr name="year_view_scrollable" format="boolean" />
       
<!--配置你喜欢的月视图显示模式模式-->
<attr name="month_view_show_mode">
<enum name="mode_all" value="0" /> <!--全部显示-->
<enum name="mode_only_current" value="1" /> <!--仅显示当前月份-->
<enum name="mode_fix" value="2" /> <!--自适应显示,不会多出一行,但是会自动填充-->
</attr>
<!-- 自定义周起始 -->
<attr name="week_start_with">
<enum name="sun" value="1" />
<enum name="mon" value="2" />
<enum name="sat" value="7" />
</attr>
<!-- 自定义选择模式 -->
<attr name="select_mode">
<enum name="default_mode" value="0" />
<enum name="single_mode" value="1" />
<enum name="range_mode" value="2" />
<enum name="multi_mode" value="3" />
</attr>
<!-- when select_mode = multi_mode -->
<attr name="max_multi_select_size" format="integer" />
<!-- 当 select_mode=range_mode -->
<attr name="min_select_range" format="integer" />
<attr name="max_select_range" format="integer" />
<!-- auto select day -->
<attr name="month_view_auto_select_day">
<enum name="first_day_of_month" value="0" />
<enum name="last_select_day" value="1" />
<enum name="last_select_day_ignore_current" value="2" />
</attr>
</declare-styleable>
```
### 写在最后,其它各种场景姿势就不多说了,看自己需求去实现。**再次注意:Demo只是Demo,只是示例如何使用,与框架本身没有关联,不属于框架一部分**
### 框架本身是为了解决各种各样的场景而设计的,UI本身是靠自己绘制的,非常简单,如果还不懂的请优先看Demo,你可以自由发挥想象力定制最喜欢的日历,只有你想不到,Demo基本给出了各种场景的实现思路。觉得可以的请给个star或者留下你宝贵的意见。
+98
View File
@@ -0,0 +1,98 @@
# CalenderView
### RecyclerView? ListView or ViewGroup? No, it's Canvas! Ultra performance and free customization interface! Fast rendering and extremely low memory.
[**Download CalendarViewDemo.apk**](https://github.com/huanghaibin-dev/CalendarView/blob/master/CalendarViewDemo.apk)
# 温馨提醒 Warm tips
Github代码全部开源无限制使用,免费开源最终版本为3.7.1,垂直、水平切换日历、自定义动画高仿iOS日历等源码不再开源。
The final version of the free and open source part is 3.7.1, the vertical and horizontal switching calendar liked iOS calendar are no longer open source.
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/screen_main.gif" height="650"/>&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/new_ios.gif" height="650"/>&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/dark_list.jpg" height="650"/>&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/screen_recorder_flip.gif" height="650"/>
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/simple.jpg" height="650"/>&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/range_select.jpg" height="650"/>&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/full_calendar.jpg" height="650"/>
### AndroidStudio v3.5+
### support version if using support package
```
implementation 'com.haibin:calendarview:3.6.8'
```
### Androidx version if using Androidx
```
implementation 'com.haibin:calendarview:3.7.1'
```
```
<dependency>
<groupId>com.haibin</groupId>
<artifactId>calendarview</artifactId>
<version>3.7.1</version>
<type>pom</type>
</dependency>
```
## How to use?
[**English Doc**](https://github.com/huanghaibin-dev/CalendarView/blob/master/QUESTION.md)
[**中文使用文档**](https://github.com/huanghaibin-dev/CalendarView/blob/master/QUESTION_ZH.md)
### proguard-rules
```java
-keepclasseswithmembers class * {
public <init>(android.content.Context);
}
```
### or using this proguard-rules
``` java
-keep class your project path.MonthView {
public <init>(android.content.Context);
}
-keep class your project path.WeekBar {
public <init>(android.content.Context);
}
-keep class your project path.WeekView {
public <init>(android.content.Context);
}
-keep class your project path.YearView {
public <init>(android.content.Context);
}
```
### Effect Preview
### func
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/main_zh_func.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/main_zh_list.png" height="650"/>
### YearView and Range Style
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/year_view.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/range.png" height="650"/>
### Beautiful Chinese style
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/custom_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/custom_shrink.png" height="650"/>
### Meizu mobile phone calendar
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/meizu_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/meizu_shrink.png" height="650"/>
### Colorful and Full style
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/full_calendar.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/color_expand.png" height="650"/>
### Progress bar style
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/progress_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/progress_shrink.png" height="650"/>
### Galaxy style
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/solar_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/solar_shrink.png" height="650"/>
## Licenses
- Copyright (C) 2013 huanghaibin_dev <huanghaibin_dev@163.com>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
limitations under the License.
+350
View File
@@ -0,0 +1,350 @@
# CalenderView
Android上一个优雅、高度自定义、性能高效的日历控件,完美支持周视图,支持标记、自定义颜色、农历等,任意控制月视图显示、任意日期拦截条件、自定义周起始等。Canvas绘制,极速性能、占用内存低,,支持简单定制即可实现任意自定义布局、自定义UI,支持收缩展开、性能非常高效,
这个控件内存和效率优势相当明显,而且真正做到收缩+展开,适配多种场景,支持同时多种颜色标记日历事务,支持多点触控,你真的想不到日历还可以如此优雅!更多参考用法请移步Demo,Demo实现了一些精美的自定义效果,用法仅供参考。
# 温馨提醒
Github代码全部开源无限制使用,免费开源最终版本为3.7.1,垂直、水平切换日历、高仿iOS日历等源码不再开源。
### 插拔式设计
插拔式设计:好比插座一样,插上灯泡就会亮,插上风扇就会转,看用户需求什么而不是看插座有什么,只要是电器即可。此框架使用插拔式,既可以在编译时指定年月日视图,如:app:month_view="xxx.xxx.MonthView.class",也可在运行时动态更换年月日视图,如:CalendarView.setMonthViewClass(MonthView.Class),从而达到UI即插即用的效果,相当于框架不提供UI实现,让UI都由客户端实现,不至于日历UI都千篇一律,只需遵守插拔式接口即可随意定制,自由化程度非常高。
[**English Version**](https://github.com/huanghaibin-dev/CalendarView/blob/master/QUESTION.md)
[**详细介绍**](https://github.com/huanghaibin-dev/CalendarView/blob/master/QUESTION_ZH.md)
### AndroidStudio v3.5+
### support版本使用
```
implementation 'com.haibin:calendarview:3.6.8
```
### Androidx版本使用
```
implementation 'com.haibin:calendarview:3.7.1'
```
```
<dependency>
<groupId>com.haibin</groupId>
<artifactId>calendarview</artifactId>
<version>3.7.0</version>
<type>pom</type>
</dependency>
```
### 混淆proguard-rules
```java
-keepclasseswithmembers class * {
public <init>(android.content.Context);
}
```
### 或者针对性的使用混淆,请自行配置测试!
``` java
-keep class your project path.MonthView {
public <init>(android.content.Context);
}
-keep class your project path.WeekBar {
public <init>(android.content.Context);
}
-keep class your project path.WeekView {
public <init>(android.content.Context);
}
-keep class your project path.YearView {
public <init>(android.content.Context);
}
```
### 效果预览
### 功能性展示
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/main_zh_func.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/main_zh_list.png" height="650"/>
### 年视图和范围选择风格
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/year_view.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/range.png" height="650"/>
### 中国式变态需求风格
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/custom_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/custom_shrink.png" height="650"/>
### 收缩展开的魅族风格效果a
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/meizu_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/meizu_shrink.png" height="650"/>
### 全屏和多彩风格
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/full_calendar.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/color_expand.png" height="650"/>
### 进度条风格
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/progress_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/progress_shrink.png" height="650"/>
### 星系图风格
<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/solar_expand.png" height="650"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="https://github.com/huanghaibin-dev/CalendarView/blob/master/app/src/main/assets/solar_shrink.png" height="650"/>
### 特别的,请注意不要复制这三个路径,自行替换您自己的自定义路径
```xml
app:month_view="com.haibin.calendarviewproject.simple.SimpleMonthView"
app:week_view="com.haibin.calendarviewproject.simple.SimpleWeekView"
app:week_bar_view="com.haibin.calendarviewproject.EnglishWeekBar"
```
### 使用方法
```xml
<com.haibin.calendarview.CalendarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:default_status="shrink"
app:calendar_show_mode="only_week_view"
app:calendar_content_view_id="@+id/recyclerView">
<com.haibin.calendarview.CalendarView
android:id="@+id/calendarView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
app:month_view="com.haibin.calendarviewproject.simple.SimpleCalendarCardView"
app:week_view="com.haibin.calendarviewproject.simple.SimpleWeekView"
app:week_bar_view="com.haibin.calendarviewproject.EnglishWeekBar"
app:calendar_height="50dp"
app:current_month_text_color="#333333"
app:current_month_lunar_text_color="#CFCFCF"
app:min_year="2004"
app:other_month_text_color="#e1e1e1"
app:scheme_text="假"
app:scheme_text_color="#333"
app:scheme_theme_color="#333"
app:selected_text_color="#fff"
app:selected_theme_color="#333"
app:week_start_with="mon"
app:week_background="#fff"
app:month_view_show_mode="mode_only_current"
app:week_text_color="#111" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d4d4d4" />
</com.haibin.calendarview.CalendarLayout>
```
### CalendarView attrs
```xml
<declare-styleable name="CalendarView">
<attr name="calendar_padding" format="dimension" /><!--日历内部左右padding-->
<attr name="month_view" format="color" /> <!--自定义类日历月视图路径-->
<attr name="week_view" format="string" /> <!--自定义类周视图路径-->
<attr name="week_bar_height" format="dimension" /> <!--星期栏的高度-->
<attr name="week_bar_view" format="color" /> <!--自定义类周栏路径,通过自定义则 week_text_color week_background xml设置无效,当仍可java api设置-->
<attr name="week_line_margin" format="dimension" /><!--线条margin-->
<attr name="week_line_background" format="color" /><!--线条颜色-->
<attr name="week_background" format="color" /> <!--星期栏的背景-->
<attr name="week_text_color" format="color" /> <!--星期栏文本颜色-->
<attr name="week_text_size" format="dimension" /><!--星期栏文本大小-->
<attr name="current_day_text_color" format="color" /> <!--今天的文本颜色-->
<attr name="current_day_lunar_text_color" format="color" /><!--今天的农历文本颜色-->
       <attr name="calendar_height" format="string" /> <!--日历每项的高度,56dp-->
<attr name="day_text_size" format="string" /> <!--天数文本大小-->
<attr name="lunar_text_size" format="string" /> <!--农历文本大小-->
<attr name="scheme_text" format="string" /> <!--标记文本-->
<attr name="scheme_text_color" format="color" /> <!--标记文本颜色-->
<attr name="scheme_month_text_color" format="color" /> <!--标记天数文本颜色-->
<attr name="scheme_lunar_text_color" format="color" /> <!--标记农历文本颜色-->
<attr name="scheme_theme_color" format="color" /> <!--标记的颜色-->
<attr name="selected_theme_color" format="color" /> <!--选中颜色-->
<attr name="selected_text_color" format="color" /> <!--选中文本颜色-->
<attr name="selected_lunar_text_color" format="color" /> <!--选中农历文本颜色-->
<attr name="current_month_text_color" format="color" /> <!--当前月份的字体颜色-->
<attr name="other_month_text_color" format="color" /> <!--其它月份的字体颜色-->
<attr name="current_month_lunar_text_color" format="color" /> <!--当前月份农历节假日颜色-->
<attr name="other_month_lunar_text_color" format="color" /> <!--其它月份农历节假日颜色-->
<!-- 年视图相关 -->
<attr name="year_view_month_text_size" format="dimension" /> <!-- 年视图月份字体大小 -->
<attr name="year_view_day_text_size" format="dimension" /> <!-- 年视图月份日期字体大小 -->
<attr name="year_view_month_text_color" format="color" /> <!-- 年视图月份字体颜色 -->
<attr name="year_view_day_text_color" format="color" /> <!-- 年视图日期字体颜色 -->
<attr name="year_view_scheme_color" format="color" /> <!-- 年视图标记颜色 -->
<attr name="min_year" format="integer" />  <!--最小年份1900-->
 <attr name="max_year" format="integer" /> <!--最大年份2099-->
<attr name="min_year_month" format="integer" /> <!--最小年份对应月份-->
<attr name="max_year_month" format="integer" /> <!--最大年份对应月份-->
<!--月视图是否可滚动-->
<attr name="month_view_scrollable" format="boolean" />
<!--周视图是否可滚动-->
<attr name="week_view_scrollable" format="boolean" />
<!--年视图是否可滚动-->
<attr name="year_view_scrollable" format="boolean" />
       
<!--配置你喜欢的月视图显示模式模式-->
<attr name="month_view_show_mode">
<enum name="mode_all" value="0" /> <!--全部显示-->
<enum name="mode_only_current" value="1" /> <!--仅显示当前月份-->
<enum name="mode_fix" value="2" /> <!--自适应显示,不会多出一行,但是会自动填充-->
</attr>
<!-- 自定义周起始 -->
<attr name="week_start_with">
<enum name="sun" value="1" />
<enum name="mon" value="2" />
<enum name="sat" value="7" />
</attr>
<!-- 自定义选择模式 -->
<attr name="select_mode">
<enum name="default_mode" value="0" />
<enum name="single_mode" value="1" />
<enum name="range_mode" value="2" />
</attr>
<!-- 当 select_mode=range_mode -->
<attr name="min_select_range" format="integer" />
<attr name="max_select_range" format="integer" />
</declare-styleable>
```
### CalendarView api
```java
public void setRange(int minYear, int minYearMonth, int minYearDay,
int maxYear, int maxYearMonth, int maxYearDay) ;//置日期范围
public int getCurDay(); //今天
public int getCurMonth(); //当前的月份
public int getCurYear(); //今年
public boolean isYearSelectLayoutVisible();//年月份选择视图是否打开
public void closeYearSelectLayout();//关闭年月视图选择布局
public void showYearSelectLayout(final int year); //快速弹出年份选择月份
public void setOnMonthChangeListener(OnMonthChangeListener listener);//月份改变事件
public void setOnYearChangeListener(OnYearChangeListener listener);//年份切换事件
public void setOnCalendarSelectListener(OnCalendarSelectListener listener)//日期选择事件
public void setOnCalendarLongClickListener(OnCalendarLongClickListener listener);//日期长按事件
public void setOnCalendarLongClickListener(OnCalendarLongClickListener listener, boolean preventLongPressedSelect);//日期长按事件
public void setOnCalendarInterceptListener(OnCalendarInterceptListener listener);//日期拦截和日期有效性绘制
public void setSchemeDate(Map<String, Calendar> mSchemeDates);//标记日期
public void update();//动态更新
public Calendar getSelectedCalendar(); //获取选择的日期
/**
* 特别的,如果你需要自定义或者使用其它选择器,可以用以下方法进行和日历联动
*/
public void scrollToCurrent();//滚动到当前日期
public void scrollToCurrent(boolean smoothScroll);//滚动到当前日期
public void scrollToYear(int year);//滚动到某一年
public void scrollToPre();//滚动到上一个月
public void scrollToNext();//滚动到下一个月
public void scrollToCalendar(int year, int month, int day);//滚动到指定日期
public Calendar getMinRangeCalendar();//获得最小范围日期
public Calendar getMaxRangeCalendar();//获得最大范围日期
/**
* 设置背景色
*
* @param monthLayoutBackground 月份卡片的背景色
* @param weekBackground 星期栏背景色
* @param lineBg 线的颜色
*/
public void setBackground(int monthLayoutBackground, int weekBackground, int lineBg)
/**
* 设置文本颜色
*
* @param curMonthTextColor 当前月份字体颜色
* @param otherMonthColor 其它月份字体颜色
* @param lunarTextColor 农历字体颜色
*/
public void setTextColor(int curMonthTextColor,int otherMonthColor,int lunarTextColor)
/**
* 设置选择的效果
*
* @param style 选中的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE
* @param selectedThemeColor 选中的标记颜色
* @param selectedTextColor 选中的字体颜色
*/
public void setSelectedColor(int style, int selectedThemeColor, int selectedTextColor)
/**
* 设置标记的色
*
* @param style 标记的style CalendarCardView.STYLE_FILL or CalendarCardView.STYLE_STROKE
* @param schemeColor 标记背景色
* @param schemeTextColor 标记字体颜色
*/
public void setSchemeColor(int style, int schemeColor, int schemeTextColor)
/**
* 设置星期栏的背景和字体颜色
*
* @param weekBackground 背景色
* @param weekTextColor 字体颜色
*/
public void setWeeColor(int weekBackground, int weekTextColor)
```
### CalendarLayout api
```java
public void expand(); //展开
public void shrink(); //收缩
public boolean isExpand();//是否展开了
```
### CalendarLayout attrs
```xml
<!-- 日历显示模式 -->
<attr name="calendar_show_mode">
<enum name="both_month_week_view" value="0" /><!-- 默认都有 -->
<enum name="only_week_view" value="1" /><!-- 仅周视图 -->
<enum name="only_month_view" value="2" /><!-- 仅月视图 -->
</attr>
<attr name="default_status">
<enum name="expand" value="0" /> <!--默认展开-->
<enum name="shrink" value="1" /><!--默认搜索-->
</attr>
<attr name="calendar_content_view_id" format="integer" /><!--内容布局id-->
```
## Licenses
- Copyright (C) 2013 huanghaibin_dev <huanghaibin_dev@163.com>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
limitations under the License.
+1
View File
@@ -0,0 +1 @@
/build
+39
View File
@@ -0,0 +1,39 @@
//noinspection GradleCompatible
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
//noinspection GradleDependency
defaultConfig {
applicationId "com.haibin.calendarviewproject"
minSdkVersion 15
//noinspection OldTargetApi
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'com.github.bumptech.glide:glide:4.5.0'
testImplementation 'junit:junit:4.12'
implementation project(':calendarview')
}
+25
View File
@@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
@@ -0,0 +1,15 @@
package com.haibin.calendarviewproject;
import org.junit.Test;
/**
* Instrumentation test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
}
}
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.haibin.calendarviewproject">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".meizu.MeiZuActivity" />
<activity android:name=".multi.MultiActivity" />
<activity android:name=".index.IndexActivity" />
<activity android:name=".simple.SimpleActivity" />
<activity android:name=".range.RangeActivity" />
<activity android:name=".colorful.ColorfulActivity" />
<activity android:name=".solay.SolarActivity" />
<activity android:name=".single.SingleActivity" />
<activity android:name=".progress.ProgressActivity" />
<activity android:name=".custom.CustomActivity" />
<activity android:name=".mix.MixActivity" />
<activity android:name=".pager.ViewPagerActivity" />
<activity android:name=".full.FullActivity" />
<activity android:name=".TestActivity" />
<activity android:name=".CalendarActivity" />
</application>
</manifest>
Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

@@ -0,0 +1,74 @@
package com.haibin.calendarviewproject;
import java.io.Serializable;
/**
* 一个简单的bean
* Created by huanghaibin on 2017/12/4.
*/
@SuppressWarnings("all")
public class Article implements Serializable {
private int id;
private String title;
private String content;
private String imgUrl;
private String desc;
private String date;
private int type;
public int getId() {
return id;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getImgUrl() {
return imgUrl;
}
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
@@ -0,0 +1,138 @@
package com.haibin.calendarviewproject;
import android.content.Context;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.haibin.calendarviewproject.group.GroupRecyclerAdapter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
* 适配器
* Created by huanghaibin on 2017/12/4.
*/
public class ArticleAdapter extends GroupRecyclerAdapter<String, Article> {
private RequestManager mLoader;
public ArticleAdapter(Context context) {
super(context);
mLoader = Glide.with(context.getApplicationContext());
LinkedHashMap<String, List<Article>> map = new LinkedHashMap<>();
List<String> titles = new ArrayList<>();
map.put("今日推荐", create(0));
map.put("每周热点", create(1));
map.put("最高评论", create(2));
titles.add("今日推荐");
titles.add("每周热点");
titles.add("最高评论");
resetGroups(map,titles);
}
@Override
protected RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type) {
return new ArticleViewHolder(mInflater.inflate(R.layout.item_list_article, parent, false));
}
@Override
protected void onBindViewHolder(RecyclerView.ViewHolder holder, Article item, int position) {
ArticleViewHolder h = (ArticleViewHolder) holder;
h.mTextTitle.setText(item.getTitle());
h.mTextContent.setText(item.getContent());
mLoader.load(item.getImgUrl())
.into(h.mImageView);
}
private static class ArticleViewHolder extends RecyclerView.ViewHolder {
private TextView mTextTitle,
mTextContent;
private ImageView mImageView;
private ArticleViewHolder(View itemView) {
super(itemView);
mTextTitle = itemView.findViewById(R.id.tv_title);
mTextContent = itemView.findViewById(R.id.tv_content);
mImageView = itemView.findViewById(R.id.imageView);
}
}
private static Article create(String title, String content, String imgUrl) {
Article article = new Article();
article.setTitle(title);
article.setContent(content);
article.setImgUrl(imgUrl);
return article;
}
private static List<Article> create(int p) {
List<Article> list = new ArrayList<>();
if (p == 0) {
list.add(create("新西兰克马德克群岛发生5.7级地震 震源深度10千米",
"#地震快讯#中国地震台网正式测定:12月04日08时08分在克马德克群岛(南纬32.82度,西经178.73度)发生5.7级地震,震源深度10千米。",
"http://cms-bucket.nosdn.127.net/catchpic/2/27/27e2ce7fd02e6c096e21b1689a8a3fe9.jpg?imageView&thumbnail=550x0"));
list.add(create("俄罗斯喊冤不当\"背锅侠\" 俄美陷入\"后真相\"旋涡",
"“差到令人震惊”,但不怪特朗普。俄罗斯总理德米特里·梅德韦杰夫近日在谈到俄美关系时这样说。俄罗斯近来连遭美国“恶毒”指责和西方国家连环出击。一些国际舆论认为,俄罗斯成了“背锅侠”,俄罗斯自己也公开喊冤斥责美国。在俄美你来我往的互掐中,真相似乎变得已不那么重要了。",
"http://cms-bucket.nosdn.127.net/catchpic/c/c8/c8b0685089258b82f3ca1997def78d8d.png?imageView&thumbnail=550x0"));
list.add(create("中企投资巴西获支持 英媒:巴西人感激\"保住饭碗\"",
"参考消息网12月4日报道 英媒称,里约热内卢附近的阿苏港曾被埃克·巴蒂斯塔称为“通往中国的公路”,10多年前,这位现已名誉扫地的巴西前首富创建了这个超级港,大宗商品热潮结束后,他在巴西的商业帝国几乎无一幸存并于2014年破产,但此后至今有一个项目仍蓬勃发展,那就是阿苏港。",
"http://cms-bucket.nosdn.127.net/catchpic/8/8b/8ba2d19b7f63efc5cf714960d5edd2c3.jpg?imageView&thumbnail=550x0"));
list.add(create("美电视台记者因误报有关弗林新闻被停职四周",
"【环球网报道】据俄罗斯卫星网12月3日报道,美国ABC电视台记者布莱恩·罗素因在有关美国总统前国家安全顾问迈克尔·弗林的新闻报道中的失误,临时被停职。",
"http://cms-bucket.nosdn.127.net/5d18566fde70407b9cc3a728822115c320171203133214.jpeg?imageView&thumbnail=550x0"));
list.add(create("预计明年3月上市 曝全新奥迪Q5L无伪谍照",
"随着之前全新一代国产奥迪Q5L在工信部目录亮相,最近曝光的测试车也都基本褪去了伪装,不过正式上市还是要等到2018年3月份。从最新曝光的内饰来看,轴距的加长令后排的空间有着非常明显的提升。",
"http://cms-bucket.nosdn.127.net/eda9ca222352470190c4f0d6b9a8c29420171201160854.jpeg?imageView&thumbnail=550x0"));
} else if (p == 1) {
list.add(create(
"2019年投产 电咖整车生产基地落户浙江绍兴",
"网易汽车11月30日报道 两周前的广州车展上,电咖发布了其首款电动汽车EV10,官方指导价为13.38万-14.18万,扣除补贴后的零售价为5.98万元-6.78万元,性价比很高。抛开车辆本身,引起业界关注的是这家新势力造车企业的几位核心成员,当年上汽大众团队的三位老兵--张海亮、向东平、牛胜福携手用了957天造了一辆可以上市的车。",
"http://cms-bucket.nosdn.127.net/674c392123254bb69bdd9227442965eb20171129203658.jpeg?imageView&thumbnail=550x0"));
list.add(create(
"2017年进入尾声,苹果大笔押注的ARkit还好么?",
"谷歌推出了AR眼镜、ARCore平台和应用在手机上的Project TangoFacebook也上线了AR开发平台和工具。至于苹果,更是把AR当做发展的重中之重。在新品iPhone8和iPhoneX中,后置摄像头专为AR进行校准,前置摄像头还添加了可以带来更好AR效果的深度传感器。",
"http://cms-bucket.nosdn.127.net/catchpic/7/76/76135ac5d3107a1d5ba11a8ee2fc7e27.jpg?imageView&thumbnail=550x0"));
list.add(create(
"亚马逊CTO:我们要让人类成为机器人的中心!",
"那些相信应用下载会让世界变得更美好的智能手机布道者和应用爱好者们,会在AWS re:Invent大会上感到不自在。亚马逊网络服务首席技术官Werner Vogels表示,所有这些都未能实现信息的民主化。",
"http://cms-bucket.nosdn.127.net/ddb758f16a7d4aa3aa422ec385fc3e5020171204081818.jpeg?imageView&thumbnail=550x0"));
list.add(create(
"有特斯拉车主想用免费的充电桩挖矿,但这可能行不通",
"在社交网络 Facebook 上的一个特斯拉车主群组中,有人开脑洞说可以尝试自己组装矿机放在特斯拉后备箱中,接入车载电池的电源,然后将车停到超级充电桩附近,就能用免费获得的电力挖矿了。",
"http://crawl.nosdn.127.net/nbotreplaceimg/4ce9c743e6c02f6777d22278e2ef8bc3/2b33e32532db204fe207693c82719660.jpg"));
} else if (p == 2) {
list.add(create(
"2017年进入尾声,苹果大笔押注的ARkit还好么?",
"谷歌推出了AR眼镜、ARCore平台和应用在手机上的Project TangoFacebook也上线了AR开发平台和工具。至于苹果,更是把AR当做发展的重中之重。在新品iPhone8和iPhoneX中,后置摄像头专为AR进行校准,前置摄像头还添加了可以带来更好AR效果的深度传感器。",
"http://cms-bucket.nosdn.127.net/catchpic/7/76/76135ac5d3107a1d5ba11a8ee2fc7e27.jpg?imageView&thumbnail=550x0"));
list.add(create(
"亚马逊CTO:我们要让人类成为机器人的中心!",
"那些相信应用下载会让世界变得更美好的智能手机布道者和应用爱好者们,会在AWS re:Invent大会上感到不自在。亚马逊网络服务首席技术官Werner Vogels表示,所有这些都未能实现信息的民主化。",
"http://cms-bucket.nosdn.127.net/ddb758f16a7d4aa3aa422ec385fc3e5020171204081818.jpeg?imageView&thumbnail=550x0"));
list.add(create("中企投资巴西获支持 英媒:巴西人感激\"保住饭碗\"",
"参考消息网12月4日报道 英媒称,里约热内卢附近的阿苏港曾被埃克·巴蒂斯塔称为“通往中国的公路”,10多年前,这位现已名誉扫地的巴西前首富创建了这个超级港,大宗商品热潮结束后,他在巴西的商业帝国几乎无一幸存并于2014年破产,但此后至今有一个项目仍蓬勃发展,那就是阿苏港。",
"http://cms-bucket.nosdn.127.net/catchpic/8/8b/8ba2d19b7f63efc5cf714960d5edd2c3.jpg?imageView&thumbnail=550x0"));
list.add(create("美电视台记者因误报有关弗林新闻被停职四周",
"【环球网报道】据俄罗斯卫星网12月3日报道,美国ABC电视台记者布莱恩·罗素因在有关美国总统前国家安全顾问迈克尔·弗林的新闻报道中的失误,临时被停职。",
"http://cms-bucket.nosdn.127.net/5d18566fde70407b9cc3a728822115c320171203133214.jpeg?imageView&thumbnail=550x0"));
list.add(create(
"2019年投产 电咖整车生产基地落户浙江绍兴",
"网易汽车11月30日报道 两周前的广州车展上,电咖发布了其首款电动汽车EV10,官方指导价为13.38万-14.18万,扣除补贴后的零售价为5.98万元-6.78万元,性价比很高。抛开车辆本身,引起业界关注的是这家新势力造车企业的几位核心成员,当年上汽大众团队的三位老兵--张海亮、向东平、牛胜福携手用了957天造了一辆可以上市的车。",
"http://cms-bucket.nosdn.127.net/674c392123254bb69bdd9227442965eb20171129203658.jpeg?imageView&thumbnail=550x0"));
}
return list;
}
}
@@ -0,0 +1,33 @@
package com.haibin.calendarviewproject;
import android.content.Context;
import android.content.Intent;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
/**
* Only calendar
* Created by haibin on 2019/6/12.
*/
public class CalendarActivity extends BaseActivity {
public static void show(Context context) {
context.startActivity(new Intent(context, CalendarActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_calendar;
}
@Override
protected void initView() {
setStatusBarDarkMode();
}
@Override
protected void initData() {
}
}
@@ -0,0 +1,78 @@
package com.haibin.calendarviewproject;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekBar;
/**
* 自定义英文栏
* Created by huanghaibin on 2017/11/30.
*/
public class EnglishWeekBar extends WeekBar {
private int mPreSelectedIndex;
public EnglishWeekBar(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.english_week_bar, this, true);
setBackgroundColor(Color.WHITE);
int padding = dipToPx(context, 10);
setPadding(padding, 0, padding, 0);
}
@Override
protected void onDateSelected(Calendar calendar, int weekStart, boolean isClick) {
getChildAt(mPreSelectedIndex).setSelected(false);
int viewIndex = getViewIndexByCalendar(calendar, weekStart);
getChildAt(viewIndex).setSelected(true);
mPreSelectedIndex = viewIndex;
}
/**
* 当周起始发生变化使用自定义布局需要重写这个方法避免出问题
*
* @param weekStart 周起始
*/
@Override
protected void onWeekStartChange(int weekStart) {
for (int i = 0; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setText(getWeekString(i, weekStart));
}
}
/**
* 或者周文本这个方法仅供父类使用
*
* @param index index
* @param weekStart weekStart
* @return 或者周文本
*/
private String getWeekString(int index, int weekStart) {
String[] weeks = getContext().getResources().getStringArray(R.array.english_week_string_array);
if (weekStart == 1) {
return weeks[index];
}
if (weekStart == 2) {
return weeks[index == 6 ? 0 : index + 1];
}
return weeks[index == 0 ? 6 : index - 1];
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,483 @@
package com.haibin.calendarviewproject;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import androidx.appcompat.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarview.TrunkBranchAnnals;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.colorful.ColorfulActivity;
import com.haibin.calendarviewproject.custom.CustomActivity;
import com.haibin.calendarviewproject.full.FullActivity;
import com.haibin.calendarviewproject.index.IndexActivity;
import com.haibin.calendarviewproject.meizu.MeiZuActivity;
import com.haibin.calendarviewproject.meizu.MeiZuMonthView;
import com.haibin.calendarviewproject.meizu.MeizuWeekView;
import com.haibin.calendarviewproject.mix.MixActivity;
import com.haibin.calendarviewproject.multi.MultiActivity;
import com.haibin.calendarviewproject.pager.ViewPagerActivity;
import com.haibin.calendarviewproject.progress.ProgressActivity;
import com.haibin.calendarviewproject.range.RangeActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import com.haibin.calendarviewproject.single.SingleActivity;
import com.haibin.calendarviewproject.solay.SolarActivity;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnCalendarLongClickListener,
CalendarView.OnMonthChangeListener,
CalendarView.OnYearChangeListener,
CalendarView.OnWeekChangeListener,
CalendarView.OnViewChangeListener,
CalendarView.OnCalendarInterceptListener,
CalendarView.OnYearViewChangeListener,
DialogInterface.OnClickListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
private AlertDialog mMoreDialog;
private AlertDialog mFuncDialog;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
//mCalendarView.setRange(2018, 7, 1, 2019, 4, 28);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.iv_more).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mMoreDialog == null) {
mMoreDialog = new AlertDialog.Builder(MainActivity.this)
.setTitle(R.string.list_dialog_title)
.setItems(R.array.list_dialog_items, MainActivity.this)
.create();
}
mMoreDialog.show();
}
});
final DialogInterface.OnClickListener listener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
mCalendarLayout.expand();
break;
case 1:
boolean result = mCalendarLayout.shrink();
Log.e("shrink", " -- " + result);
break;
case 2:
mCalendarView.scrollToPre(false);
break;
case 3:
mCalendarView.scrollToNext(false);
break;
case 4:
//mCalendarView.scrollToCurrent(true);
mCalendarView.scrollToCalendar(2018, 12, 30);
break;
case 5:
mCalendarView.setRange(2018, 7, 1, 2019, 4, 28);
// mCalendarView.setRange(mCalendarView.getCurYear(), mCalendarView.getCurMonth(), 6,
// mCalendarView.getCurYear(), mCalendarView.getCurMonth(), 23);
break;
case 6:
Log.e("scheme", " " + mCalendarView.getSelectedCalendar().getScheme() + " -- "
+ mCalendarView.getSelectedCalendar().isCurrentDay());
List<Calendar> weekCalendars = mCalendarView.getCurrentWeekCalendars();
for (Calendar calendar : weekCalendars) {
Log.e("onWeekChange", calendar.toString() + " -- " + calendar.getScheme());
}
new AlertDialog.Builder(MainActivity.this)
.setMessage(String.format("Calendar Range: \n%s —— %s",
mCalendarView.getMinRangeCalendar(),
mCalendarView.getMaxRangeCalendar()))
.show();
break;
}
}
};
findViewById(R.id.iv_func).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mFuncDialog == null) {
mFuncDialog = new AlertDialog.Builder(MainActivity.this)
.setTitle(R.string.func_dialog_title)
.setItems(R.array.func_dialog_items, listener)
.create();
}
mFuncDialog.show();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnYearChangeListener(this);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnMonthChangeListener(this);
mCalendarView.setOnCalendarLongClickListener(this, true);
mCalendarView.setOnWeekChangeListener(this);
mCalendarView.setOnYearViewChangeListener(this);
//设置日期拦截事件仅适用单选模式当前无效
mCalendarView.setOnCalendarInterceptListener(this);
mCalendarView.setOnViewChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@SuppressWarnings("unused")
@Override
protected void initData() {
final int year = mCalendarView.getCurYear();
final int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
for (int y = 1997; y < 2082; y++) {
for (int m = 1; m <= 12; m++) {
map.put(getSchemeCalendar(y, m, 1, 0xFF40db25, "").toString(),
getSchemeCalendar(y, m, 1, 0xFF40db25, ""));
map.put(getSchemeCalendar(y, m, 2, 0xFFe69138, "").toString(),
getSchemeCalendar(y, m, 2, 0xFFe69138, ""));
map.put(getSchemeCalendar(y, m, 3, 0xFFdf1356, "").toString(),
getSchemeCalendar(y, m, 3, 0xFFdf1356, ""));
map.put(getSchemeCalendar(y, m, 4, 0xFFaacc44, "").toString(),
getSchemeCalendar(y, m, 4, 0xFFaacc44, ""));
map.put(getSchemeCalendar(y, m, 5, 0xFFbc13f0, "").toString(),
getSchemeCalendar(y, m, 5, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(y, m, 6, 0xFF542261, "").toString(),
getSchemeCalendar(y, m, 6, 0xFF542261, ""));
map.put(getSchemeCalendar(y, m, 7, 0xFF4a4bd2, "").toString(),
getSchemeCalendar(y, m, 7, 0xFF4a4bd2, ""));
map.put(getSchemeCalendar(y, m, 8, 0xFFe69138, "").toString(),
getSchemeCalendar(y, m, 8, 0xFFe69138, ""));
map.put(getSchemeCalendar(y, m, 9, 0xFF542261, "").toString(),
getSchemeCalendar(y, m, 9, 0xFF542261, ""));
map.put(getSchemeCalendar(y, m, 10, 0xFF87af5a, "").toString(),
getSchemeCalendar(y, m, 10, 0xFF87af5a, ""));
map.put(getSchemeCalendar(y, m, 11, 0xFF40db25, "").toString(),
getSchemeCalendar(y, m, 11, 0xFF40db25, ""));
map.put(getSchemeCalendar(y, m, 12, 0xFFcda1af, "").toString(),
getSchemeCalendar(y, m, 12, 0xFFcda1af, ""));
map.put(getSchemeCalendar(y, m, 13, 0xFF95af1a, "").toString(),
getSchemeCalendar(y, m, 13, 0xFF95af1a, ""));
map.put(getSchemeCalendar(y, m, 14, 0xFF33aadd, "").toString(),
getSchemeCalendar(y, m, 14, 0xFF33aadd, ""));
map.put(getSchemeCalendar(y, m, 15, 0xFF1aff1a, "").toString(),
getSchemeCalendar(y, m, 15, 0xFF1aff1a, ""));
map.put(getSchemeCalendar(y, m, 16, 0xFF22acaf, "").toString(),
getSchemeCalendar(y, m, 16, 0xFF22acaf, ""));
map.put(getSchemeCalendar(y, m, 17, 0xFF99a6fa, "").toString(),
getSchemeCalendar(y, m, 17, 0xFF99a6fa, ""));
map.put(getSchemeCalendar(y, m, 18, 0xFFe69138, "").toString(),
getSchemeCalendar(y, m, 18, 0xFFe69138, ""));
map.put(getSchemeCalendar(y, m, 19, 0xFF40db25, "").toString(),
getSchemeCalendar(y, m, 19, 0xFF40db25, ""));
map.put(getSchemeCalendar(y, m, 20, 0xFFe69138, "").toString(),
getSchemeCalendar(y, m, 20, 0xFFe69138, ""));
map.put(getSchemeCalendar(y, m, 21, 0xFF40db25, "").toString(),
getSchemeCalendar(y, m, 21, 0xFF40db25, ""));
map.put(getSchemeCalendar(y, m, 22, 0xFF99a6fa, "").toString(),
getSchemeCalendar(y, m, 22, 0xFF99a6fa, ""));
map.put(getSchemeCalendar(y, m, 23, 0xFF33aadd, "").toString(),
getSchemeCalendar(y, m, 23, 0xFF33aadd, ""));
map.put(getSchemeCalendar(y, m, 24, 0xFF40db25, "").toString(),
getSchemeCalendar(y, m, 24, 0xFF40db25, ""));
map.put(getSchemeCalendar(y, m, 25, 0xFF1aff1a, "").toString(),
getSchemeCalendar(y, m, 25, 0xFF1aff1a, ""));
map.put(getSchemeCalendar(y, m, 26, 0xFF40db25, "").toString(),
getSchemeCalendar(y, m, 26, 0xFF40db25, ""));
map.put(getSchemeCalendar(y, m, 27, 0xFF95af1a, "").toString(),
getSchemeCalendar(y, m, 27, 0xFF95af1a, ""));
map.put(getSchemeCalendar(y, m, 28, 0xFF40db25, "").toString(),
getSchemeCalendar(y, m, 28, 0xFF40db25, ""));
}
}
//28560 数据量增长不会影响UI响应速度请使用这个API替换
mCalendarView.setSchemeDate(map);
//可自行测试性能差距
//mCalendarView.setSchemeDate(schemes);
findViewById(R.id.ll_flyme).setOnClickListener(this);
findViewById(R.id.ll_simple).setOnClickListener(this);
findViewById(R.id.ll_range).setOnClickListener(this);
findViewById(R.id.ll_mix).setOnClickListener(this);
findViewById(R.id.ll_colorful).setOnClickListener(this);
findViewById(R.id.ll_index).setOnClickListener(this);
findViewById(R.id.ll_tab).setOnClickListener(this);
findViewById(R.id.ll_single).setOnClickListener(this);
findViewById(R.id.ll_multi).setOnClickListener(this);
findViewById(R.id.ll_solar_system).setOnClickListener(this);
findViewById(R.id.ll_progress).setOnClickListener(this);
findViewById(R.id.ll_custom).setOnClickListener(this);
findViewById(R.id.ll_full).setOnClickListener(this);
}
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
mCalendarView.setWeekStarWithSun();
break;
case 1:
mCalendarView.setWeekStarWithMon();
break;
case 2:
mCalendarView.setWeekStarWithSat();
break;
case 3:
if (mCalendarView.isSingleSelectMode()) {
mCalendarView.setSelectDefaultMode();
} else {
mCalendarView.setSelectSingleMode();
}
break;
case 4:
mCalendarView.setWeekView(MeizuWeekView.class);
mCalendarView.setMonthView(MeiZuMonthView.class);
mCalendarView.setWeekBar(EnglishWeekBar.class);
break;
case 5:
mCalendarView.setAllMode();
break;
case 6:
mCalendarView.setOnlyCurrentMode();
break;
case 7:
mCalendarView.setFixMode();
break;
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
MeiZuActivity.show(this);
//CalendarActivity.show(this);
break;
case R.id.ll_custom:
CustomActivity.show(this);
break;
case R.id.ll_mix:
MixActivity.show(this);
break;
case R.id.ll_full:
FullActivity.show(this);
break;
case R.id.ll_range:
RangeActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
case R.id.ll_tab:
ViewPagerActivity.show(this);
break;
case R.id.ll_single:
SingleActivity.show(this);
break;
case R.id.ll_multi:
MultiActivity.show(this);
break;
case R.id.ll_solar_system:
SolarActivity.show(this);
break;
case R.id.ll_progress:
ProgressActivity.show(this);
break;
}
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
return calendar;
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
Toast.makeText(this, String.format("%s : OutOfRange", calendar), Toast.LENGTH_SHORT).show();
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
//Log.e("onDateSelected", " -- " + calendar.getYear() + " -- " + calendar.getMonth() + " -- " + calendar.getDay());
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
if (isClick) {
Toast.makeText(this, getCalendarText(calendar), Toast.LENGTH_SHORT).show();
}
// Log.e("lunar "," -- " + calendar.getLunarCalendar().toString() + "\n" +
// " -- " + calendar.getLunarCalendar().getYear());
Log.e("onDateSelected", " -- " + calendar.getYear() +
" -- " + calendar.getMonth() +
" -- " + calendar.getDay() +
" -- " + isClick + " -- " + calendar.getScheme());
Log.e("onDateSelected", " " + mCalendarView.getSelectedCalendar().getScheme() +
" -- " + mCalendarView.getSelectedCalendar().isCurrentDay());
Log.e("干支年纪 ", " -- " + TrunkBranchAnnals.getTrunkBranchYear(calendar.getLunarCalendar().getYear()));
}
@Override
public void onCalendarLongClickOutOfRange(Calendar calendar) {
Toast.makeText(this, String.format("%s : LongClickOutOfRange", calendar), Toast.LENGTH_SHORT).show();
}
@Override
public void onCalendarLongClick(Calendar calendar) {
Toast.makeText(this, "长按不选择日期\n" + getCalendarText(calendar), Toast.LENGTH_SHORT).show();
}
private static String getCalendarText(Calendar calendar) {
return String.format("新历%s \n 农历%s \n 公历节日:%s \n 农历节日:%s \n 节气:%s \n 是否闰月:%s",
calendar.getMonth() + "" + calendar.getDay() + "",
calendar.getLunarCalendar().getMonth() + "" + calendar.getLunarCalendar().getDay() + "",
TextUtils.isEmpty(calendar.getGregorianFestival()) ? "" : calendar.getGregorianFestival(),
TextUtils.isEmpty(calendar.getTraditionFestival()) ? "" : calendar.getTraditionFestival(),
TextUtils.isEmpty(calendar.getSolarTerm()) ? "" : calendar.getSolarTerm(),
calendar.getLeapMonth() == 0 ? "" : String.format("闰%s月", calendar.getLeapMonth()));
}
@SuppressLint("SetTextI18n")
@Override
public void onMonthChange(int year, int month) {
Log.e("onMonthChange", " -- " + year + " -- " + month);
Calendar calendar = mCalendarView.getSelectedCalendar();
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
}
@Override
public void onViewChange(boolean isMonthView) {
Log.e("onViewChange", " --- " + (isMonthView ? "月视图" : "周视图"));
}
@Override
public void onWeekChange(List<Calendar> weekCalendars) {
for (Calendar calendar : weekCalendars) {
Log.e("onWeekChange", calendar.toString());
}
}
@Override
public void onYearViewChange(boolean isClose) {
Log.e("onYearViewChange", "年视图 -- " + (isClose ? "关闭" : "打开"));
}
/**
* 屏蔽某些不可点击的日期可根据自己的业务自行修改
*
* @param calendar calendar
* @return 是否屏蔽某些不可点击的日期MonthView和WeekView有类似的API可调用
*/
@Override
public boolean onCalendarIntercept(Calendar calendar) {
Log.e("onCalendarIntercept", calendar.toString());
int day = calendar.getDay();
return day == 1 || day == 3 || day == 6 || day == 11 || day == 12 || day == 15 || day == 20 || day == 26;
}
@Override
public void onCalendarInterceptClick(Calendar calendar, boolean isClick) {
Toast.makeText(this, calendar.toString() + "拦截不可点击", Toast.LENGTH_SHORT).show();
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
Log.e("onYearChange", " 年份变化 " + year);
}
}
@@ -0,0 +1,51 @@
package com.haibin.calendarviewproject;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
/**
* 测试界面
* Created by huanghaibin on 2018/8/7.
*/
public class TestActivity extends BaseActivity implements View.OnClickListener {
private CalendarView mCalendarView;
public static void show(Context context) {
context.startActivity(new Intent(context, TestActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_test;
}
@Override
protected void initView() {
setStatusBarDarkMode();
findViewById(R.id.iv_next).setOnClickListener(this);
findViewById(R.id.iv_pre).setOnClickListener(this);
mCalendarView = findViewById(R.id.calendar_view);
}
@Override
protected void initData() {
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_next:
mCalendarView.scrollToNext(false);
break;
case R.id.iv_pre:
mCalendarView.scrollToPre(false);
break;
}
}
}
@@ -0,0 +1,147 @@
package com.haibin.calendarviewproject.base.activity;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 基类
* Created by huanghaibin on 2017/11/16.
*/
public abstract class BaseActivity extends AppCompatActivity {
private static boolean isMiUi = false;
protected void initWindow() {
}
protected abstract int getLayoutId();
protected abstract void initView();
protected abstract void initData();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initWindow();
setContentView(getLayoutId());
initView();
initData();
}
/**
* 设置小米黑色状态栏字体
*/
@SuppressLint("PrivateApi")
private void setMIUIStatusBarDarkMode() {
if (isMiUi) {
Class<? extends Window> clazz = getWindow().getClass();
try {
int darkModeFlag;
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(getWindow(), darkModeFlag, darkModeFlag);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
* 静态域获取系统版本是否基于MIUI
*/
static {
try {
@SuppressLint("PrivateApi") Class<?> sysClass = Class.forName("android.os.SystemProperties");
Method getStringMethod = sysClass.getDeclaredMethod("get", String.class);
String version = (String) getStringMethod.invoke(sysClass, "ro.miui.ui.version.name");
isMiUi = version.compareTo("V6") >= 0 && Build.VERSION.SDK_INT < 24;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置魅族手机状态栏图标颜色风格
* 可以用来判断是否为Flyme用户
*
* @param window 需要设置的窗口
* @param dark 是否把状态栏字体及图标颜色设置为深色
* @return boolean 成功执行返回true
*/
@SuppressWarnings("JavaReflectionMemberAccess")
public static boolean setMeiZuDarkMode(Window window, boolean dark) {
boolean result = false;
if (Build.VERSION.SDK_INT >= 24) {
return false;
}
if (window != null) {
try {
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class
.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
@SuppressLint("InlinedApi")
private int getStatusBarLightMode() {
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (isMiUi) {
result = 1;
} else if (setMeiZuDarkMode(getWindow(), true)) {
result = 2;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
result = 3;
}
}
return result;
}
@SuppressLint("InlinedApi")
protected void setStatusBarDarkMode() {
int type = getStatusBarLightMode();
if (type == 1) {
setMIUIStatusBarDarkMode();
} else if (type == 2) {
setMeiZuDarkMode(getWindow(), true);
} else if (type == 3) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
}
}
@@ -0,0 +1,139 @@
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.haibin.calendarviewproject.base.adapter;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* 基本的适配器
*/
@SuppressWarnings("unused")
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter {
protected LayoutInflater mInflater;
protected List<T> mItems;
private OnItemClickListener onItemClickListener;
private OnClickListener onClickListener;
public BaseRecyclerAdapter(Context context) {
this.mItems = new ArrayList<>();
mInflater = LayoutInflater.from(context);
onClickListener = new OnClickListener() {
@Override
public void onClick(int position, long itemId) {
if (onItemClickListener != null)
onItemClickListener.onItemClick(position, itemId);
}
};
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final RecyclerView.ViewHolder holder = onCreateDefaultViewHolder(parent, viewType);
holder.itemView.setTag(holder);
holder.itemView.setOnClickListener(onClickListener);
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
onBindViewHolder(holder, mItems.get(position), position);
}
protected abstract RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type);
protected abstract void onBindViewHolder(RecyclerView.ViewHolder holder, T item, int position);
@Override
public int getItemCount() {
return mItems.size();
}
void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
void addAll(List<T> items) {
if (items != null && items.size() > 0) {
mItems.addAll(items);
notifyItemRangeInserted(mItems.size(), items.size());
}
}
final void addItem(T item) {
if (item != null) {
this.mItems.add(item);
notifyItemChanged(mItems.size());
}
}
final List<T> getItems() {
return mItems;
}
final T getItem(int position) {
if (position < 0 || position >= mItems.size())
return null;
return mItems.get(position);
}
static abstract class OnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder) v.getTag();
onClick(holder.getAdapterPosition(), holder.getItemId());
}
public abstract void onClick(int position, long itemId);
}
interface OnItemClickListener {
void onItemClick(int position, long itemId);
}
public final void removeItem(T item) {
if (this.mItems.contains(item)) {
int position = mItems.indexOf(item);
this.mItems.remove(item);
notifyItemRemoved(position);
}
}
protected final void removeItem(int position) {
if (this.getItemCount() > position) {
this.mItems.remove(position);
notifyItemRemoved(position);
}
}
protected final void clear(){
mItems.clear();
notifyDataSetChanged();
}
}
@@ -0,0 +1,52 @@
package com.haibin.calendarviewproject.base.fragment;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public abstract class BaseFragment extends Fragment {
protected View mRootView;
protected LayoutInflater mInflater;
protected Context mContext;
@Override
public void onAttach(Context context) {
mContext = context;
super.onAttach(context);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (mRootView != null) {
ViewGroup parent = (ViewGroup) mRootView.getParent();
if (parent != null)
parent.removeView(mRootView);
} else {
mRootView = inflater.inflate(getLayoutId(), container, false);
mInflater = inflater;
initView();
initData();
}
return mRootView;
}
@Override
public void onDetach() {
mContext = null;
super.onDetach();
}
protected abstract int getLayoutId();
protected abstract void initView();
protected abstract void initData();
}
@@ -0,0 +1,94 @@
package com.haibin.calendarviewproject.base.fragment;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentTransaction;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("unused")
public class FragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragment = new ArrayList<>();
private final FragmentManager mFragmentManager;
private boolean mUpdateFlag;
private Fragment mCurFragment;
private String[] mTitles;
public FragmentAdapter(FragmentManager fm) {
super(fm);
this.mFragmentManager = fm;
}
public boolean isUpdateFlag() {
return mUpdateFlag;
}
public void setUpdateFlag(boolean mUpdateFlag) {
this.mUpdateFlag = mUpdateFlag;
}
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
if (mUpdateFlag) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
String tag = fragment.getTag();
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.remove(fragment);
fragment = getItem(position);
if (!fragment.isAdded()) {
transaction.add(container.getId(), fragment, tag)
.attach(fragment)
.commitAllowingStateLoss();
}
return fragment;
}
return super.instantiateItem(container, position);
}
public void reset(List<Fragment> fragments) {
mFragment.clear();
mFragment.addAll(fragments);
}
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
if (object instanceof Fragment) {
mCurFragment = (Fragment) object;
}
}
public Fragment getCurFragment() {
return mCurFragment;
}
public void reset(String[] titles) {
this.mTitles = titles;
}
@Override
public Fragment getItem(int position) {
return mFragment.get(position);
}
@Override
public int getCount() {
return mFragment.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
@@ -0,0 +1,185 @@
package com.haibin.calendarviewproject.colorful;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
import com.haibin.calendarviewproject.index.IndexActivity;
import com.haibin.calendarviewproject.meizu.MeiZuActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import java.util.HashMap;
import java.util.Map;
public class ColorfulActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnYearChangeListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
GroupRecyclerView mRecyclerView;
public static void show(Context context) {
context.startActivity(new Intent(context, ColorfulActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_colorful;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(this));
mRecyclerView.notifyDataSetChanged();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
MeiZuActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
}
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
return calendar;
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
}
@@ -0,0 +1,76 @@
package com.haibin.calendarviewproject.colorful;
import android.content.Context;
import android.graphics.Canvas;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MonthView;
/**
* 高仿魅族日历布局
* Created by huanghaibin on 2017/11/15.
*/
public class ColorfulMonthView extends MonthView {
private int mRadius;
public ColorfulMonthView(Context context) {
super(context);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
}
/**
* 如果需要点击Scheme没有效果则return true
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return false 则不绘制onDrawScheme因为这里背景色是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = y - mItemHeight / 8;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint : mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint : mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint : mCurMonthLunarTextPaint);
}
}
}
@@ -0,0 +1,85 @@
package com.haibin.calendarviewproject.colorful;
import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.view.View;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekView;
/**
* 多彩周视图
* Created by huanghaibin on 2017/11/29.
*/
public class ColorfulWeekView extends WeekView {
private int mRadius;
public ColorfulWeekView(Context context) {
super(context);
// //兼容硬件加速无效的代码
// setLayerType(View.LAYER_TYPE_SOFTWARE, mSelectedPaint);
// //4.0以上硬件加速会导致无效
// mSelectedPaint.setMaskFilter(new BlurMaskFilter(30, BlurMaskFilter.Blur.SOLID));
//
// setLayerType(View.LAYER_TYPE_SOFTWARE, mSchemePaint);
// mSchemePaint.setMaskFilter(new BlurMaskFilter(30, BlurMaskFilter.Blur.SOLID));
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
}
/**
* 如果需要点击Scheme没有效果则return true
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return false 则不绘制onDrawScheme因为这里背景色是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = -mItemHeight / 8;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint : mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint : mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mSchemeTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mCurMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint : mCurMonthLunarTextPaint);
}
}
}
@@ -0,0 +1,204 @@
package com.haibin.calendarviewproject.custom;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.colorful.ColorfulActivity;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
import com.haibin.calendarviewproject.index.IndexActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import java.util.HashMap;
import java.util.Map;
public class CustomActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnYearChangeListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
GroupRecyclerView mRecyclerView;
public static void show(Context context) {
context.startActivity(new Intent(context, CustomActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_custom;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
//mCalendarView.addSchemeDate(getSchemeCalendar(2019, 6, 1, 0xFF40db25, ""));
// int year = 2019;
// int month = 6;
// Map<String, Calendar> map = new HashMap<>();
// map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
// getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
// map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
// getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
// map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
// getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
// map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
// getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
// mCalendarView.addSchemeDate(map);
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(this));
mRecyclerView.notifyDataSetChanged();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
CustomActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
}
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
calendar.addScheme(new Calendar.Scheme());
calendar.addScheme(0xFF008800, "");
calendar.addScheme(0xFF008800, "");
return calendar;
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
Log.e("onDateSelected", " -- " + calendar.getYear() +
" -- " + calendar.getMonth() +
" -- " + calendar.getDay() +
" -- " + isClick + " -- " + calendar.getScheme());
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
}
@@ -0,0 +1,194 @@
package com.haibin.calendarviewproject.custom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextUtils;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MonthView;
/**
* 演示一个变态需求的月视图
* Created by huanghaibin on 2018/2/9.
*/
public class CustomMonthView extends MonthView {
private int mRadius;
/**
* 自定义魅族标记的文本画笔
*/
private Paint mTextPaint = new Paint();
/**
* 24节气画笔
*/
private Paint mSolarTermTextPaint = new Paint();
/**
* 背景圆点
*/
private Paint mPointPaint = new Paint();
/**
* 今天的背景色
*/
private Paint mCurrentDayPaint = new Paint();
/**
* 圆点半径
*/
private float mPointRadius;
private int mPadding;
private float mCircleRadius;
/**
* 自定义魅族标记的圆形背景
*/
private Paint mSchemeBasicPaint = new Paint();
private float mSchemeBaseLine;
public CustomMonthView(Context context) {
super(context);
mTextPaint.setTextSize(dipToPx(context, 8));
mTextPaint.setColor(0xffffffff);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSolarTermTextPaint.setColor(0xff489dff);
mSolarTermTextPaint.setAntiAlias(true);
mSolarTermTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setFakeBoldText(true);
mSchemeBasicPaint.setColor(Color.WHITE);
mCurrentDayPaint.setAntiAlias(true);
mCurrentDayPaint.setStyle(Paint.Style.FILL);
mCurrentDayPaint.setColor(0xFFeaeaea);
mPointPaint.setAntiAlias(true);
mPointPaint.setStyle(Paint.Style.FILL);
mPointPaint.setTextAlign(Paint.Align.CENTER);
mPointPaint.setColor(Color.RED);
mCircleRadius = dipToPx(getContext(), 7);
mPadding = dipToPx(getContext(), 3);
mPointRadius = dipToPx(context, 2);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mCircleRadius - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);
}
@Override
protected void onPreviewHook() {
mSolarTermTextPaint.setTextSize(mCurMonthLunarTextPaint.getTextSize());
mRadius = Math.min(mItemWidth, mItemHeight) / 11 * 5;
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
boolean isSelected = isSelected(calendar);
if (isSelected) {
mPointPaint.setColor(Color.WHITE);
} else {
mPointPaint.setColor(Color.GRAY);
}
canvas.drawCircle(x + mItemWidth / 2, y + mItemHeight - 3 * mPadding, mPointRadius, mPointPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
int top = y - mItemHeight / 6;
if (calendar.isCurrentDay() && !isSelected) {
canvas.drawCircle(cx, cy, mRadius, mCurrentDayPaint);
}
if (hasScheme) {
canvas.drawCircle(x + mItemWidth - mPadding - mCircleRadius / 2, y + mPadding + mCircleRadius, mCircleRadius, mSchemeBasicPaint);
mTextPaint.setColor(calendar.getSchemeColor());
canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mCircleRadius, y + mPadding + mSchemeBaseLine, mTextPaint);
}
//当然可以换成其它对应的画笔就不麻烦
if (calendar.isWeekend() && calendar.isCurrentMonth()) {
mCurMonthTextPaint.setColor(0xFF489dff);
mCurMonthLunarTextPaint.setColor(0xFF489dff);
mSchemeTextPaint.setColor(0xFF489dff);
mSchemeLunarTextPaint.setColor(0xFF489dff);
mOtherMonthLunarTextPaint.setColor(0xFF489dff);
mOtherMonthTextPaint.setColor(0xFF489dff);
} else {
mCurMonthTextPaint.setColor(0xff333333);
mCurMonthLunarTextPaint.setColor(0xffCFCFCF);
mSchemeTextPaint.setColor(0xff333333);
mSchemeLunarTextPaint.setColor(0xffCFCFCF);
mOtherMonthTextPaint.setColor(0xFFe1e1e1);
mOtherMonthLunarTextPaint.setColor(0xFFe1e1e1);
}
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
!TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint : mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? !TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint :
mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,64 @@
package com.haibin.calendarviewproject.custom;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekBar;
import com.haibin.calendarviewproject.R;
/**
* 自定义英文栏
* Created by huanghaibin on 2017/11/30.
*/
public class CustomWeekBar extends WeekBar {
private int mPreSelectedIndex;
public CustomWeekBar(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.custom_week_bar, this, true);
setBackgroundColor(Color.WHITE);
}
@Override
protected void onDateSelected(Calendar calendar, int weekStart, boolean isClick) {
getChildAt(mPreSelectedIndex).setSelected(false);
int viewIndex = getViewIndexByCalendar(calendar, weekStart);
getChildAt(viewIndex).setSelected(true);
mPreSelectedIndex = viewIndex;
}
/**
* 当周起始发生变化使用自定义布局需要重写这个方法避免出问题
*
* @param weekStart 周起始
*/
@Override
protected void onWeekStartChange(int weekStart) {
for (int i = 0; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setText(getWeekString(i, weekStart));
}
}
/**
* 或者周文本这个方法仅供父类使用
* @param index index
* @param weekStart weekStart
* @return 或者周文本
*/
private String getWeekString(int index, int weekStart) {
String[] weeks = getContext().getResources().getStringArray(R.array.chinese_week_string_array);
if (weekStart == 1) {
return weeks[index];
}
if (weekStart == 2) {
return weeks[index == 6 ? 0 : index + 1];
}
return weeks[index == 0 ? 6 : index - 1];
}
}
@@ -0,0 +1,200 @@
package com.haibin.calendarviewproject.custom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextUtils;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekView;
/**
* 演示一个变态需求的周视图
* Created by huanghaibin on 2018/2/9.
*/
public class CustomWeekView extends WeekView {
private int mRadius;
/**
* 自定义魅族标记的文本画笔
*/
private Paint mTextPaint = new Paint();
/**
* 24节气画笔
*/
private Paint mSolarTermTextPaint = new Paint();
/**
* 背景圆点
*/
private Paint mPointPaint = new Paint();
/**
* 今天的背景色
*/
private Paint mCurrentDayPaint = new Paint();
/**
* 圆点半径
*/
private float mPointRadius;
private int mPadding;
private float mCircleRadius;
/**
* 自定义魅族标记的圆形背景
*/
private Paint mSchemeBasicPaint = new Paint();
private float mSchemeBaseLine;
public CustomWeekView(Context context) {
super(context);
mTextPaint.setTextSize(dipToPx(context, 8));
mTextPaint.setColor(0xffffffff);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSolarTermTextPaint.setColor(0xff489dff);
mSolarTermTextPaint.setAntiAlias(true);
mSolarTermTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setFakeBoldText(true);
mSchemeBasicPaint.setColor(Color.WHITE);
mPointPaint.setAntiAlias(true);
mPointPaint.setStyle(Paint.Style.FILL);
mPointPaint.setTextAlign(Paint.Align.CENTER);
mPointPaint.setColor(Color.RED);
mCurrentDayPaint.setAntiAlias(true);
mCurrentDayPaint.setStyle(Paint.Style.FILL);
mCurrentDayPaint.setColor(0xFFeaeaea);
mCircleRadius = dipToPx(getContext(), 7);
mPadding = dipToPx(getContext(), 3);
mPointRadius = dipToPx(context, 2);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mCircleRadius - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);
}
@Override
protected void onPreviewHook() {
mSolarTermTextPaint.setTextSize(mCurMonthLunarTextPaint.getTextSize());
mRadius = Math.min(mItemWidth, mItemHeight) / 11 * 5;
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
boolean isSelected = isSelected(calendar);
if (isSelected) {
mPointPaint.setColor(Color.WHITE);
} else {
mPointPaint.setColor(Color.GRAY);
}
canvas.drawCircle(x + mItemWidth / 2, mItemHeight - 3 * mPadding, mPointRadius, mPointPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
int top = -mItemHeight / 6;
if (calendar.isCurrentDay() && !isSelected) {
canvas.drawCircle(cx, cy, mRadius, mCurrentDayPaint);
}
if(hasScheme){
canvas.drawCircle(x + mItemWidth - mPadding - mCircleRadius / 2, mPadding + mCircleRadius, mCircleRadius, mSchemeBasicPaint);
mTextPaint.setColor(calendar.getSchemeColor());
canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mCircleRadius, mPadding + mSchemeBaseLine, mTextPaint);
}
if (calendar.isWeekend() && calendar.isCurrentMonth()) {
mCurMonthTextPaint.setColor(0xFF489dff);
mCurMonthLunarTextPaint.setColor(0xFF489dff);
mSchemeTextPaint.setColor(0xFF489dff);
mSchemeLunarTextPaint.setColor(0xFF489dff);
mOtherMonthLunarTextPaint.setColor(0xFF489dff);
mOtherMonthTextPaint.setColor(0xFF489dff);
} else {
mCurMonthTextPaint.setColor(0xff333333);
mCurMonthLunarTextPaint.setColor(0xffCFCFCF);
mSchemeTextPaint.setColor(0xff333333);
mSchemeLunarTextPaint.setColor(0xffCFCFCF);
mOtherMonthTextPaint.setColor(0xFFe1e1e1);
mOtherMonthLunarTextPaint.setColor(0xFFe1e1e1);
}
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
!TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint : mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
!TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint :
calendar.isCurrentMonth() ?
mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,142 @@
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.haibin.calendarviewproject.custom;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.YearView;
/**
* 自定义年视图
* Created by huanghaibin on 2018/10/9.
*/
@SuppressWarnings("unused")
public class CustomYearView extends YearView {
private int mTextPadding;
/**
* 闰年字体
*/
private Paint mLeapYearTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public CustomYearView(Context context) {
super(context);
mTextPadding = dipToPx(context, 3);
mLeapYearTextPaint.setTextSize(dipToPx(context, 12));
mLeapYearTextPaint.setColor(0xffd1d1d1);
mLeapYearTextPaint.setAntiAlias(true);
mLeapYearTextPaint.setFakeBoldText(true);
}
@Override
protected void onDrawMonth(Canvas canvas, int year, int month, int x, int y, int width, int height) {
String text = getContext()
.getResources()
.getStringArray(com.haibin.calendarview.R.array.month_string_array)[month - 1];
canvas.drawText(text,
x + mItemWidth / 2 - mTextPadding,
y + mMonthTextBaseLine,
mMonthTextPaint);
if (month == 2 && isLeapYear(year)) {
float w = getTextWidth(mMonthTextPaint, text);
canvas.drawText("闰年",
x + mItemWidth / 2 - mTextPadding + w + dipToPx(getContext(), 6),
y + mMonthTextBaseLine,
mLeapYearTextPaint);
}
}
private float getTextWidth(Paint paint, String text) {
return paint.measureText(text);
}
/**
* 是否是闰年
*
* @param year year
* @return 是否是闰年
*/
private static boolean isLeapYear(int year) {
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
@Override
protected void onDrawWeek(Canvas canvas, int week, int x, int y, int width, int height) {
String text = getContext().getResources().getStringArray(com.haibin.calendarview.R.array.year_view_week_string_array)[week];
canvas.drawText(text,
x + width / 2,
y + mWeekTextBaseLine,
mWeekTextPaint);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
int radius = Math.min(mItemWidth, mItemHeight) / 8 * 5;
canvas.drawCircle(cx, cy, radius, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine + y;
int cx = x + mItemWidth / 2;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
hasScheme ? mSchemeTextPaint : mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint : mSchemeTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint : mCurMonthTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,175 @@
package com.haibin.calendarviewproject.full;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.colorful.ColorfulActivity;
import com.haibin.calendarviewproject.custom.CustomActivity;
import com.haibin.calendarviewproject.index.IndexActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import java.util.HashMap;
import java.util.Map;
/**
* 全屏日历,因为月份大小不同的关系需要 app:month_view_show_mode="mode_all"
* 一般地既然使用全屏日历那也不必要
* Created by huanghaibin on 2019/3/7.
*/
public class FullActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnYearChangeListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
private int mYear;
CalendarView mCalendarView;
public static void show(Context context) {
context.startActivity(new Intent(context, FullActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_full;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mCalendarView = findViewById(R.id.calendarView);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
}
});
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 22, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 22, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
calendar.addScheme(color, "");
calendar.addScheme(day%2 == 0 ? 0xFF00CD00 : 0xFFD15FEE, "");
calendar.addScheme(day%2 == 0 ? 0xFF660000 : 0xFF4169E1, "");
return calendar;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
CustomActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
}
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
Log.e("onDateSelected", " -- " + calendar.getYear() +
" -- " + calendar.getMonth() +
" -- " + calendar.getDay() +
" -- " + isClick + " -- " + calendar.getScheme());
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
}
@@ -0,0 +1,142 @@
package com.haibin.calendarviewproject.full;
import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MonthView;
import java.util.List;
/**
* 高仿魅族日历布局
* Created by huanghaibin on 2017/11/15.
*/
public class FullMonthView extends MonthView {
private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/**
* 自定义魅族标记的圆形背景
*/
private Paint mSchemeBasicPaint = new Paint();
public FullMonthView(Context context) {
super(context);
mRectPaint.setStyle(Paint.Style.STROKE);
mRectPaint.setStrokeWidth(dipToPx(context, 0.5f));
mRectPaint.setColor(0x88efefef);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setFakeBoldText(true);
//兼容硬件加速无效的代码
setLayerType(View.LAYER_TYPE_SOFTWARE, mSchemeBasicPaint);
//4.0以上硬件加速会导致无效
mSelectedPaint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.SOLID));
}
/**
* 绘制选中的日子
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return true 则绘制onDrawScheme因为这里背景色不是是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
canvas.drawRect(x, y , x + mItemWidth, y + mItemHeight, mSelectedPaint);
return true;
}
/**
* 绘制标记的事件日子
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
List<Calendar.Scheme> schemes = calendar.getSchemes();
if (schemes == null || schemes.size() == 0) {
return;
}
int space = dipToPx(getContext(), 2);
int indexY = y + mItemHeight - 2 * space;
int sw = dipToPx(getContext(), mItemWidth / 10);
int sh = dipToPx(getContext(), 4);
for (Calendar.Scheme scheme : schemes) {
mSchemePaint.setColor(scheme.getShcemeColor());
canvas.drawRect(x + mItemWidth - sw - 2 * space,
indexY - sh, x + mItemWidth - 2 * space, indexY, mSchemePaint);
indexY = indexY - space -sh;
}
}
/**
* 绘制文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
canvas.drawRect(x, y, x + mItemWidth, y + mItemHeight, mRectPaint);
int cx = x + mItemWidth / 2;
int top = y - mItemHeight / 6;
boolean isInRange = isInRange(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() && isInRange ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() && isInRange ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,119 @@
package com.haibin.calendarviewproject.full;
import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekView;
import java.util.List;
/**
* 魅族周视图
* Created by huanghaibin on 2017/11/29.
*/
public class FullWeekView extends WeekView {
private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mSchemeBasicPaint = new Paint();
public FullWeekView(Context context) {
super(context);
mRectPaint.setStyle(Paint.Style.STROKE);
mRectPaint.setStrokeWidth(dipToPx(context, 0.5f));
mRectPaint.setColor(0x88efefef);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xffed5353);
mSchemeBasicPaint.setFakeBoldText(true);
//兼容硬件加速无效的代码
setLayerType(View.LAYER_TYPE_SOFTWARE, mSchemeBasicPaint);
//4.0以上硬件加速会导致无效
mSelectedPaint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.SOLID));
}
/**
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return true 则绘制onDrawScheme因为这里背景色不是是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x,0, x + mItemWidth, mItemHeight , mSelectedPaint);
return true;
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
List<Calendar.Scheme> schemes = calendar.getSchemes();
if (schemes == null || schemes.size() == 0) {
return;
}
int space = dipToPx(getContext(), 2);
int indexY = mItemHeight - 2 * space;
int sw = dipToPx(getContext(), mItemWidth / 10);
int sh = dipToPx(getContext(), 4);
for (Calendar.Scheme scheme : schemes) {
mSchemePaint.setColor(scheme.getShcemeColor());
canvas.drawRect(x + mItemWidth - sw - 2 * space,
indexY - sh, x + mItemWidth - 2 * space, indexY, mSchemePaint);
indexY = indexY - space -sh;
}
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
canvas.drawRect(x, 0, x + mItemWidth, mItemHeight, mRectPaint);
int cx = x + mItemWidth / 2;
int top = - mItemHeight / 6;
boolean isInRange = isInRange(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() && isInRange ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() && isInRange ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,282 @@
package com.haibin.calendarviewproject.group;
import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import java.util.HashMap;
import java.util.Map;
/**
* 分组浮动的ItemDecoration
* Created by haibin on 2017/5/15.
*/
@SuppressWarnings("all")
public class GroupItemDecoration<Group, Child> extends RecyclerView.ItemDecoration {
protected int mGroupHeight;
protected int mGroutBackground;
protected Paint mBackgroundPaint;
protected Paint mTextPaint;
protected float mTextBaseLine;
protected int mPaddingLeft, mPaddingRight;
protected boolean isCenter;
protected boolean isHasHeader;
protected int mChildItemOffset;
@SuppressLint("UseSparseArrays")
protected Map<Integer, Group> mGroup = new HashMap<>();
public GroupItemDecoration() {
super();
init();
}
private void init() {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(0xFFf5f7f8);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mBackgroundPaint.setAntiAlias(true);
mTextPaint = new Paint();
mTextPaint.setColor(0xFF353535);
mTextPaint.setAntiAlias(true);
}
/**
* 先于RecyclerView的Item onDraw调用
*
* @param c RecyclerView canvas
* @param parent RecyclerView
* @param state stare
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
onDrawGroup(c, parent);
}
/**
* 绘制分组Group
*
* @param c Canvas
* @param parent RecyclerView
*/
protected void onDrawGroup(Canvas c, RecyclerView parent) {
int paddingLeft = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int top, bottom;
int count = parent.getChildCount();
for (int i = 0; i < parent.getChildCount(); i++) {
View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int key = params.getViewLayoutPosition();
if (mGroup.containsKey(key)) {
top = child.getTop() - params.topMargin - mGroupHeight;
bottom = top + mGroupHeight;
c.drawRect(paddingLeft, top, right, bottom, mBackgroundPaint);
String group = mGroup.get(params.getViewLayoutPosition()).toString();
float x;
float y = top + mTextBaseLine;
if (isCenter) {
x = parent.getMeasuredWidth() / 2 - getTextX(group);
} else {
x = mPaddingLeft;
}
c.drawText(group, x, y, mTextPaint);
}
}
}
/**
* 后于RecyclerView的Item onDraw调用
*
* @param c RecyclerView canvas
* @param parent RecyclerView
* @param state stare
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
onDrawOverGroup(c, parent);
}
/**
* 绘制悬浮组
*
* @param c Canvas
* @param parent RecyclerView
*/
protected void onDrawOverGroup(Canvas c, RecyclerView parent) {
int firstVisiblePosition = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();
if (firstVisiblePosition == RecyclerView.NO_POSITION) {
return;
}
Group group = getCroup(firstVisiblePosition);
if (group == null)
return;
String groupTitle = group.toString();
if (TextUtils.isEmpty(groupTitle)) {
return;
}
boolean isRestore = false;
Group nextGroup = getCroup(firstVisiblePosition + 1);
if (nextGroup != null && !group.equals(nextGroup)) {
//说明是当前组最后一个元素但不一定碰撞了
View child = parent.findViewHolderForAdapterPosition(firstVisiblePosition).itemView;
if (child.getTop() + child.getMeasuredHeight() < mGroupHeight) {
//进一步检测碰撞
c.save();//保存画布当前的状态
isRestore = true;
c.translate(0, child.getTop() + child.getMeasuredHeight() - mGroupHeight);
}
}
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int top = parent.getPaddingTop();
int bottom = top + mGroupHeight;
c.drawRect(left, top, right, bottom, mBackgroundPaint);
float x;
float y = top + mTextBaseLine;
if (isCenter) {
x = parent.getMeasuredWidth() / 2 - getTextX(groupTitle);
} else {
x = mPaddingLeft;
}
c.drawText(groupTitle, x, y, mTextPaint);
if (isRestore) {
//还原画布为初始状态
c.restore();
}
}
/**
* 设置item的上下左右偏移量
*
* @param outRect rect
* @param view item
* @param parent RecyclerView
* @param state stare
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
getItemOffsets(outRect, view, parent, parent.getChildViewHolder(view).getAdapterPosition());
}
/**
* 设置item的上下左右偏移量不做任何处理就是默认状态
*
* @param outRect outRect
* @param view view
* @param parent RecyclerView
* @param adapterPosition position
*/
protected void getItemOffsets(Rect outRect, View view, RecyclerView parent, int adapterPosition) {
if (mGroup.containsKey(adapterPosition)) {
outRect.set(0, mGroupHeight, 0, mGroup.containsKey(adapterPosition + 1) ? 0 : mChildItemOffset);
} else {
outRect.set(0, 0, 0, mGroup.containsKey(adapterPosition + 1) ? 0 : mChildItemOffset);
}
}
/**
* 获得当前ViewPosition所在的组
*
* @param position 当前View的position
* @return 当前ViewPosition所在的组
*/
protected Group getCroup(int position) {
while (position >= 0) {
if (mGroup.containsKey(position)) {
return mGroup.get(position);
}
position--;
}
return null;
}
/**
* 通知更新分组信息
*
* @param adapter GroupRecyclerAdapter
*/
public void notifyDataSetChanged(GroupRecyclerAdapter<Group, Child> adapter) {
mGroup.clear();
if (adapter == null) return;
int key = 0;
for (int i = 0; i < adapter.getGroupCount(); i++) {
if (i == 0) {
mGroup.put(isHasHeader ? 1 : 0, adapter.getGroup(i));
key += adapter.getChildCount(i) + (isHasHeader ? 1 : 0);
;
} else {
mGroup.put(key, adapter.getGroup(i));
key += adapter.getChildCount(i);
}
}
}
public void setChildItemOffset(int childItemOffset){
this.mChildItemOffset = childItemOffset;
}
public void setBackground(int groupBackground) {
mBackgroundPaint.setColor(groupBackground);
}
public void setTextColor(int textColor) {
mTextPaint.setColor(textColor);
}
public void setTextSize(float textSize) {
mTextPaint.setTextSize(textSize);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
mTextBaseLine = mGroupHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2;
}
public void setGroupHeight(int groupHeight) {
mGroupHeight = groupHeight;
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
mTextBaseLine = mGroupHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2;
}
public void setPadding(int mPaddingLeft, int mPaddingRight) {
this.mPaddingLeft = mPaddingLeft;
this.mPaddingRight = mPaddingRight;
}
public void setCenter(boolean isCenter) {
this.isCenter = isCenter;
}
public void setHasHeader(boolean hasHeader) {
isHasHeader = hasHeader;
}
/**
* 获取文本的x坐标起点
*
* @param str 文本
* @return x
*/
protected float getTextX(String str) {
Rect bounds = new Rect();
mTextPaint.getTextBounds(str, 0, str.length(), bounds);
return bounds.width() / 2;
}
/**
* 获取文本的长度像素
* @param str 文本
* @return px
*/
protected float getTextLenghtPx(String str) {
Rect bounds = new Rect();
mTextPaint.getTextBounds(str, 0, str.length(), bounds);
return bounds.width();
}
}
@@ -0,0 +1,135 @@
package com.haibin.calendarviewproject.group;
import android.content.Context;
import com.haibin.calendarviewproject.base.adapter.BaseRecyclerAdapter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
* 分组的RecyclerAdapter
* Created by haibin on 2017/5/15.
*/
@SuppressWarnings("unused")
public abstract class GroupRecyclerAdapter<Parent, Child> extends BaseRecyclerAdapter<Child> {
private LinkedHashMap<Parent, List<Child>> mGroups;
private List<Parent> mGroupTitles;
public GroupRecyclerAdapter(Context context) {
super(context);
mGroups = new LinkedHashMap<>();
mGroupTitles = new ArrayList<>();
}
/**
* 返回特定的标题
*/
Parent getGroup(int groupPosition) {
return mGroupTitles.get(groupPosition);
}
/**
* 获得分组的数量
*
* @return 组的数量
*/
int getGroupCount() {
return mGroupTitles.size();
}
/**
* 获取某一组的数量
*
* @param groupPosition groupPosition
* @return 某一组的数量
*/
int getChildCount(int groupPosition) {
if (mGroupTitles == null || mGroups.size() == 0)
return 0;
if (mGroups.get(mGroupTitles.get(groupPosition)) == null)
return 0;
return mGroups.get(mGroupTitles.get(groupPosition)).size();
}
/**
* 重置分组数据
*
* @param groups groups
* @param titles titles
*/
protected void resetGroups(LinkedHashMap<Parent, List<Child>> groups, List<Parent> titles) {
if (groups == null || titles == null) {
return;
}
mGroups.clear();
mGroupTitles.clear();
mGroups.putAll(groups);
mGroupTitles.addAll(titles);
mItems.clear();
for (Parent key : mGroups.keySet()) {
mItems.addAll(mGroups.get(key));
}
notifyDataSetChanged();
}
/**
* 清除分组数据
*/
public final void clearGroup() {
mGroupTitles.clear();
mGroups.clear();
clear();
}
/**
* 从分组移除数据
*
* @param position 下标
* @return 分组是否为空要移除分组
*/
public boolean removeGroupItem(int position) {
int group = getGroupIndex(position);
removeGroupChildren(group);
int count = getChildCount(group);
removeItem(position);
if (count <= 0) {
mGroupTitles.remove(group);
return true;
}
return false;
}
/**
* 获取所在分组
*
* @param position 下标
* @return 获取所在分组
*/
private int getGroupIndex(int position) {
int count = 0;
if (position <= count)
return 0;
int i = 0;
for (Parent parent : mGroups.keySet()) {
count += mGroups.get(parent).size();
if (position < count) {
return i;
}
i++;
}
return 0;
}
private void removeGroupChildren(int groupPosition) {
if (groupPosition >= mGroupTitles.size())
return;
List<Child> childList = mGroups.get(mGroupTitles.get(groupPosition));
if (childList != null && childList.size() != 0) {
childList.remove(childList.size() - 1);
}
}
}
@@ -0,0 +1,91 @@
package com.haibin.calendarviewproject.group;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import com.haibin.calendarviewproject.R;
/**
* 带分组浮动的RecyclerView
* Created by haibin on 2017/5/15.
*/
@SuppressWarnings("all")
public class GroupRecyclerView extends RecyclerView {
private GroupItemDecoration mItemDecoration;
private int mGroupHeight;
private int mGroutBackground, mTextColor;
private int mTextSize;
private int mPaddingLeft, mPaddingRight;
private boolean isCenter;
protected int mChildItemOffset;
private boolean isHasHeader;
private OnGroupChangeListener mListener;
public GroupRecyclerView(Context context) {
super(context);
}
public GroupRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.GroupRecyclerView);
mTextSize = array.getDimensionPixelSize(R.styleable.GroupRecyclerView_group_text_size, 16);
mGroupHeight = (int) array.getDimension(R.styleable.GroupRecyclerView_group_height, 52);
mChildItemOffset = (int) array.getDimension(R.styleable.GroupRecyclerView_group_child_offset, 20);
mTextColor = array.getColor(R.styleable.GroupRecyclerView_group_text_color, 0xFFFFFFFF);
mGroutBackground = array.getColor(R.styleable.GroupRecyclerView_group_background, 0x80000000);
isCenter = array.getBoolean(R.styleable.GroupRecyclerView_group_center, false);
isHasHeader = array.getBoolean(R.styleable.GroupRecyclerView_group_has_header, true);
mPaddingLeft = (int) array.getDimension(R.styleable.GroupRecyclerView_group_padding_left, 16);
mPaddingRight = (int) array.getDimension(R.styleable.GroupRecyclerView_group_padding_right, 16);
array.recycle();
}
@Override
public void setAdapter(Adapter adapter) {
if (adapter instanceof GroupRecyclerAdapter) {
super.setAdapter(adapter);
} else {
throw new IllegalStateException("Adapter must instanceof " +
"GroupRecyclerAdapter or extends GroupRecyclerAdapter");
}
}
@Override
public void addItemDecoration(ItemDecoration decor) {
if (decor instanceof GroupItemDecoration)
super.addItemDecoration(decor);
else
throw new IllegalStateException("ItemDecoration must instanceof " +
"GroupItemDecoration or extends GroupItemDecoration");
mItemDecoration = (GroupItemDecoration) decor;
mItemDecoration.setTextSize(mTextSize);
mItemDecoration.setBackground(mGroutBackground);
mItemDecoration.setTextColor(mTextColor);
mItemDecoration.setGroupHeight(mGroupHeight);
mItemDecoration.setPadding(mPaddingLeft, mPaddingRight);
mItemDecoration.setCenter(isCenter);
mItemDecoration.setHasHeader(isHasHeader);
mItemDecoration.setChildItemOffset(mChildItemOffset);
//mItemDecoration.notifyDataSetChanged((GroupRecyclerAdapter) getAdapter());
}
public void notifyDataSetChanged() {
mItemDecoration.notifyDataSetChanged((GroupRecyclerAdapter) getAdapter());
}
public void setOnGroupChangeListener(OnGroupChangeListener listener) {
this.mListener = listener;
}
/**
* 分组最上面改变通知
*/
public interface OnGroupChangeListener {
void onGroupChange(int groupPosition, String group);
}
}
@@ -0,0 +1,196 @@
package com.haibin.calendarviewproject.index;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.colorful.ColorfulActivity;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
import com.haibin.calendarviewproject.meizu.MeiZuActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import java.util.HashMap;
import java.util.Map;
public class IndexActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnCalendarLongClickListener,
CalendarView.OnYearChangeListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
GroupRecyclerView mRecyclerView;
public static void show(Context context) {
context.startActivity(new Intent(context, IndexActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_index;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mCalendarView.setOnCalendarLongClickListener(this,false);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(this));
mRecyclerView.notifyDataSetChanged();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
MeiZuActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
}
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
return calendar;
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
}
@Override
public void onCalendarLongClickOutOfRange(Calendar calendar) {
}
@Override
public void onCalendarLongClick(Calendar calendar) {
Log.e("onDateLongClick", " -- " + calendar.getDay() + " -- " + calendar.getMonth());
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
}
@@ -0,0 +1,91 @@
package com.haibin.calendarviewproject.index;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MonthView;
/**
* 下标标记的日历控件
* Created by huanghaibin on 2017/11/15.
*/
public class IndexMonthView extends MonthView {
private Paint mSchemeBasicPaint = new Paint();
private int mPadding;
private int mH, mW;
public IndexMonthView(Context context) {
super(context);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xff333333);
mSchemeBasicPaint.setFakeBoldText(true);
mPadding = dipToPx(getContext(), 4);
mH = dipToPx(getContext(), 2);
mW = dipToPx(getContext(), 8);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);
return true;
}
/**
* onDrawSelected
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawRect(x + mItemWidth / 2 - mW / 2,
y + mItemHeight - mH * 2 - mPadding,
x + mItemWidth / 2 + mW / 2,
y + mItemHeight - mH - mPadding, mSchemeBasicPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = y - mItemHeight / 6;
if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,103 @@
package com.haibin.calendarviewproject.index;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekView;
/**
* 下标周视图
* Created by huanghaibin on 2017/11/29.
*/
public class IndexWeekView extends WeekView {
private Paint mSchemeBasicPaint = new Paint();
private int mPadding;
private int mH, mW;
public IndexWeekView(Context context) {
super(context);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xff333333);
mSchemeBasicPaint.setFakeBoldText(true);
mPadding = dipToPx(getContext(), 4);
mH = dipToPx(getContext(), 2);
mW = dipToPx(getContext(), 8);
}
@Override
protected void onPreviewHook() {
}
/**
* 如果这里和 onDrawScheme 是互斥的 return false
* return true 会先绘制 onDrawSelected再绘制onDrawSelected
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint);
return true;
}
/**
* 绘制下标标记
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawRect(x + mItemWidth / 2 - mW / 2,
mItemHeight - mH * 2 - mPadding,
x + mItemWidth / 2 + mW / 2,
mItemHeight - mH - mPadding, mSchemeBasicPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = -mItemHeight / 6;
if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mCurMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mCurMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
mCurMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,171 @@
package com.haibin.calendarviewproject.meizu;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
import java.util.HashMap;
import java.util.Map;
public class MeiZuActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnYearChangeListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
GroupRecyclerView mRecyclerView;
public static void show(Context context) {
context.startActivity(new Intent(context, MeiZuActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_meizu;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(this));
mRecyclerView.notifyDataSetChanged();
}
@Override
public void onClick(View v) {
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
calendar.addScheme(new Calendar.Scheme());
calendar.addScheme(0xFF008800, "");
calendar.addScheme(0xFF008800, "");
return calendar;
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
}
@@ -0,0 +1,141 @@
package com.haibin.calendarviewproject.meizu;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MonthView;
/**
* 高仿魅族日历布局
* Created by huanghaibin on 2017/11/15.
*/
public class MeiZuMonthView extends MonthView {
/**
* 自定义魅族标记的文本画笔
*/
private Paint mTextPaint = new Paint();
/**
* 自定义魅族标记的圆形背景
*/
private Paint mSchemeBasicPaint = new Paint();
private float mRadio;
private int mPadding;
private float mSchemeBaseLine;
public MeiZuMonthView(Context context) {
super(context);
mTextPaint.setTextSize(dipToPx(context, 8));
mTextPaint.setColor(0xffffffff);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setFakeBoldText(true);
mRadio = dipToPx(getContext(), 7);
mPadding = dipToPx(getContext(), 4);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);
// //兼容硬件加速无效的代码
// setLayerType(View.LAYER_TYPE_SOFTWARE, mSchemeBasicPaint);
// //4.0以上硬件加速会导致无效
// mSchemeBasicPaint.setMaskFilter(new BlurMaskFilter(25, BlurMaskFilter.Blur.SOLID));
}
/**
* 绘制选中的日子
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return true 则绘制onDrawScheme因为这里背景色不是是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);
return true;
}
/**
* 绘制标记的事件日子
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, y + mPadding + mRadio, mRadio, mSchemeBasicPaint);
canvas.drawText(calendar.getScheme(),
x + mItemWidth - mPadding - mRadio / 2 - getTextWidth(calendar.getScheme()) / 2,
y + mPadding + mSchemeBaseLine, mTextPaint);
}
private float getTextWidth(String text) {
return mTextPaint.measureText(text);
}
/**
* 绘制文本
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
* @param hasScheme 是否是标记的日期
* @param isSelected 是否选中
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = y - mItemHeight / 6;
boolean isInRange = isInRange(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() && isInRange ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() && isInRange ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,109 @@
package com.haibin.calendarviewproject.meizu;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekView;
/**
* 魅族周视图
* Created by huanghaibin on 2017/11/29.
*/
public class MeizuWeekView extends WeekView {
private Paint mTextPaint = new Paint();
private Paint mSchemeBasicPaint = new Paint();
private float mRadio;
private int mPadding;
private float mSchemeBaseLine;
public MeizuWeekView(Context context) {
super(context);
mTextPaint.setTextSize(dipToPx(context, 8));
mTextPaint.setColor(0xffffffff);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xffed5353);
mSchemeBasicPaint.setFakeBoldText(true);
mRadio = dipToPx(getContext(), 7);
mPadding = dipToPx(getContext(), 4);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mRadio - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);
}
/**
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
* @return true 则绘制onDrawScheme因为这里背景色不是是互斥的
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawCircle(x + mItemWidth - mPadding - mRadio / 2, mPadding + mRadio, mRadio, mSchemeBasicPaint);
canvas.drawText(calendar.getScheme(),
x + mItemWidth - mPadding - mRadio / 2 - getTextWidth(calendar.getScheme()) / 2,
mPadding + mSchemeBaseLine, mTextPaint);
}
private float getTextWidth(String text) {
return mTextPaint.measureText(text);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = -mItemHeight / 6;
boolean isInRange = isInRange(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() && isInRange ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() && isInRange ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() && isInRange ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,203 @@
package com.haibin.calendarviewproject.mix;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.colorful.ColorfulActivity;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
import com.haibin.calendarviewproject.index.IndexActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import java.util.HashMap;
import java.util.Map;
public class MixActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnYearChangeListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
GroupRecyclerView mRecyclerView;
public static void show(Context context) {
context.startActivity(new Intent(context, MixActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_mix;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mCalendarView.setOnClickCalendarPaddingListener(new CalendarView.OnClickCalendarPaddingListener() {
@Override
public void onClickCalendarPadding(float x, float y, boolean isMonthView,
Calendar adjacentCalendar, Object obj) {
Log.e("onClickCalendarPadding", " -- " + x + " " + y + " " + obj + " " + adjacentCalendar);
Toast.makeText(MixActivity.this,
adjacentCalendar.getYear() + "年,第" + obj + "",
Toast.LENGTH_SHORT).show();
}
});
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(this));
mRecyclerView.notifyDataSetChanged();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
MixActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
}
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
calendar.addScheme(new Calendar.Scheme());
calendar.addScheme(0xFF008800, "");
calendar.addScheme(0xFF008800, "");
return calendar;
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
Log.e("onDateSelected", " -- " + calendar.getYear() +
" -- " + calendar.getMonth() +
" -- " + calendar.getDay() +
" -- " + isClick + " -- " + calendar.getScheme());
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
}
@@ -0,0 +1,219 @@
package com.haibin.calendarviewproject.mix;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextUtils;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarUtil;
import com.haibin.calendarview.MonthView;
/**
* 演示一个变态需求的月视图
* Created by huanghaibin on 2018/2/9.
*/
public class MixMonthView extends MonthView {
private int mRadius;
/**
* 自定义魅族标记的文本画笔
*/
private Paint mTextPaint = new Paint();
/**
* 24节气画笔
*/
private Paint mSolarTermTextPaint = new Paint();
/**
* 背景圆点
*/
private Paint mPointPaint = new Paint();
/**
* 今天的背景色
*/
private Paint mCurrentDayPaint = new Paint();
/**
* 圆点半径
*/
private float mPointRadius;
private int mPadding;
private float mCircleRadius;
/**
* 自定义魅族标记的圆形背景
*/
private Paint mSchemeBasicPaint = new Paint();
private float mSchemeBaseLine;
public MixMonthView(Context context) {
super(context);
mTextPaint.setTextSize(dipToPx(context, 8));
mTextPaint.setColor(0xffffffff);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSolarTermTextPaint.setColor(0xff489dff);
mSolarTermTextPaint.setAntiAlias(true);
mSolarTermTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setFakeBoldText(true);
mSchemeBasicPaint.setColor(Color.WHITE);
mCurrentDayPaint.setAntiAlias(true);
mCurrentDayPaint.setStyle(Paint.Style.FILL);
mCurrentDayPaint.setColor(0xFFeaeaea);
mPointPaint.setAntiAlias(true);
mPointPaint.setStyle(Paint.Style.FILL);
mPointPaint.setTextAlign(Paint.Align.CENTER);
mPointPaint.setColor(Color.RED);
mCircleRadius = dipToPx(getContext(), 7);
mPadding = dipToPx(getContext(), 3);
mPointRadius = dipToPx(context, 2);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mCircleRadius - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);
}
@Override
protected void onPreviewHook() {
mSolarTermTextPaint.setTextSize(mCurMonthLunarTextPaint.getTextSize());
mRadius = Math.min(mItemWidth, mItemHeight) / 11 * 5;
}
@Override
protected Object getClickCalendarPaddingObject(float x, float y,Calendar adjacentCalendar) {
return CalendarUtil.getWeekCountBetweenBothCalendar(mYear, 1, 1,
mYear, adjacentCalendar.getMonth(), adjacentCalendar.getDay(), getWeekStartWith());
}
@Override
protected void onDraw(Canvas canvas) {
int weekStart = CalendarUtil.getWeekCountBetweenBothCalendar(mYear, 1, 1,
mYear, mMonth, 1, getWeekStartWith());
int weekEnd = CalendarUtil.getWeekCountBetweenBothCalendar(mYear, 1, 1,
mYear, mMonth, CalendarUtil.getMonthDaysCount(mYear, mMonth), getWeekStartWith());
int width = dipToPx(getContext(), 52);//left-padding
int cx = width / 2;
int cy = 0;
for (int w = weekStart; w <= weekEnd; w++) {
canvas.drawText(String.valueOf(w), cx, mTextBaseLine + cy,
mOtherMonthTextPaint);
cy += mItemHeight;
}
super.onDraw(canvas);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
boolean isSelected = isSelected(calendar);
if (isSelected) {
mPointPaint.setColor(Color.WHITE);
} else {
mPointPaint.setColor(Color.GRAY);
}
canvas.drawCircle(x + mItemWidth / 2, y + mItemHeight - 3 * mPadding, mPointRadius, mPointPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
int top = y - mItemHeight / 6;
if (calendar.isCurrentDay() && !isSelected) {
canvas.drawCircle(cx, cy, mRadius, mCurrentDayPaint);
}
if (hasScheme) {
canvas.drawCircle(x + mItemWidth - mPadding - mCircleRadius / 2, y + mPadding + mCircleRadius, mCircleRadius, mSchemeBasicPaint);
mTextPaint.setColor(calendar.getSchemeColor());
canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mCircleRadius, y + mPadding + mSchemeBaseLine, mTextPaint);
}
//当然可以换成其它对应的画笔就不麻烦
if (calendar.isWeekend() && calendar.isCurrentMonth()) {
mCurMonthTextPaint.setColor(0xFF489dff);
mCurMonthLunarTextPaint.setColor(0xFF489dff);
mSchemeTextPaint.setColor(0xFF489dff);
mSchemeLunarTextPaint.setColor(0xFF489dff);
mOtherMonthLunarTextPaint.setColor(0xFF489dff);
mOtherMonthTextPaint.setColor(0xFF489dff);
} else {
mCurMonthTextPaint.setColor(0xff333333);
mCurMonthLunarTextPaint.setColor(0xffCFCFCF);
mSchemeTextPaint.setColor(0xff333333);
mSchemeLunarTextPaint.setColor(0xffCFCFCF);
mOtherMonthTextPaint.setColor(0xFFe1e1e1);
mOtherMonthLunarTextPaint.setColor(0xFFe1e1e1);
}
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
!TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint : mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
calendar.isCurrentMonth() ? !TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint :
mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,64 @@
package com.haibin.calendarviewproject.mix;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekBar;
import com.haibin.calendarviewproject.R;
/**
* 自定义英文栏
* Created by huanghaibin on 2017/11/30.
*/
public class MixWeekBar extends WeekBar {
private int mPreSelectedIndex;
public MixWeekBar(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.custom_week_bar, this, true);
setBackgroundColor(Color.WHITE);
}
@Override
protected void onDateSelected(Calendar calendar, int weekStart, boolean isClick) {
getChildAt(mPreSelectedIndex).setSelected(false);
int viewIndex = getViewIndexByCalendar(calendar, weekStart);
getChildAt(viewIndex).setSelected(true);
mPreSelectedIndex = viewIndex;
}
/**
* 当周起始发生变化使用自定义布局需要重写这个方法避免出问题
*
* @param weekStart 周起始
*/
@Override
protected void onWeekStartChange(int weekStart) {
for (int i = 0; i < getChildCount(); i++) {
((TextView) getChildAt(i)).setText(getWeekString(i, weekStart));
}
}
/**
* 或者周文本这个方法仅供父类使用
* @param index index
* @param weekStart weekStart
* @return 或者周文本
*/
private String getWeekString(int index, int weekStart) {
String[] weeks = getContext().getResources().getStringArray(R.array.chinese_week_string_array);
if (weekStart == 1) {
return weeks[index];
}
if (weekStart == 2) {
return weeks[index == 6 ? 0 : index + 1];
}
return weeks[index == 0 ? 6 : index - 1];
}
}
@@ -0,0 +1,224 @@
package com.haibin.calendarviewproject.mix;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextUtils;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarUtil;
import com.haibin.calendarview.WeekView;
/**
* 演示一个变态需求的周视图
* Created by huanghaibin on 2018/2/9.
*/
public class MixWeekView extends WeekView {
private int mRadius;
/**
* 自定义魅族标记的文本画笔
*/
private Paint mTextPaint = new Paint();
/**
* 24节气画笔
*/
private Paint mSolarTermTextPaint = new Paint();
/**
* 背景圆点
*/
private Paint mPointPaint = new Paint();
/**
* 今天的背景色
*/
private Paint mCurrentDayPaint = new Paint();
/**
* 圆点半径
*/
private float mPointRadius;
private int mPadding;
private float mCircleRadius;
/**
* 自定义魅族标记的圆形背景
*/
private Paint mSchemeBasicPaint = new Paint();
private float mSchemeBaseLine;
public MixWeekView(Context context) {
super(context);
mTextPaint.setTextSize(dipToPx(context, 8));
mTextPaint.setColor(0xffffffff);
mTextPaint.setAntiAlias(true);
mTextPaint.setFakeBoldText(true);
mSolarTermTextPaint.setColor(0xff489dff);
mSolarTermTextPaint.setAntiAlias(true);
mSolarTermTextPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setFakeBoldText(true);
mSchemeBasicPaint.setColor(Color.WHITE);
mPointPaint.setAntiAlias(true);
mPointPaint.setStyle(Paint.Style.FILL);
mPointPaint.setTextAlign(Paint.Align.CENTER);
mPointPaint.setColor(Color.RED);
mCurrentDayPaint.setAntiAlias(true);
mCurrentDayPaint.setStyle(Paint.Style.FILL);
mCurrentDayPaint.setColor(0xFFeaeaea);
mCircleRadius = dipToPx(getContext(), 7);
mPadding = dipToPx(getContext(), 3);
mPointRadius = dipToPx(context, 2);
Paint.FontMetrics metrics = mSchemeBasicPaint.getFontMetrics();
mSchemeBaseLine = mCircleRadius - metrics.descent + (metrics.bottom - metrics.top) / 2 + dipToPx(getContext(), 1);
}
@Override
protected void onDraw(Canvas canvas) {
if (mItems == null || mItems.size() == 0) {
return;
}
Calendar calendar = mItems.get(0);
int weekStart = CalendarUtil.getWeekCountBetweenBothCalendar(calendar.getYear(), 1, 1,
calendar.getYear(), calendar.getMonth(), calendar.getDay(), getWeekStartWith());
int width = dipToPx(getContext(), 52);
int cx = width / 2;
int cy = 0;
canvas.drawText(String.valueOf(weekStart), cx, mTextBaseLine + cy,
mOtherMonthTextPaint);
super.onDraw(canvas);
}
@Override
protected Object getClickCalendarPaddingObject(float x, float y, Calendar adjacentCalendar) {
return CalendarUtil.getWeekCountBetweenBothCalendar(adjacentCalendar.getYear(), 1, 1,
adjacentCalendar.getYear(), adjacentCalendar.getMonth(), adjacentCalendar.getDay(), getWeekStartWith());
}
@Override
protected void onPreviewHook() {
mSolarTermTextPaint.setTextSize(mCurMonthLunarTextPaint.getTextSize());
mRadius = Math.min(mItemWidth, mItemHeight) / 11 * 5;
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return true;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
boolean isSelected = isSelected(calendar);
if (isSelected) {
mPointPaint.setColor(Color.WHITE);
} else {
mPointPaint.setColor(Color.GRAY);
}
canvas.drawCircle(x + mItemWidth / 2, mItemHeight - 3 * mPadding, mPointRadius, mPointPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
int top = -mItemHeight / 6;
if (calendar.isCurrentDay() && !isSelected) {
canvas.drawCircle(cx, cy, mRadius, mCurrentDayPaint);
}
if (hasScheme) {
canvas.drawCircle(x + mItemWidth - mPadding - mCircleRadius / 2, mPadding + mCircleRadius, mCircleRadius, mSchemeBasicPaint);
mTextPaint.setColor(calendar.getSchemeColor());
canvas.drawText(calendar.getScheme(), x + mItemWidth - mPadding - mCircleRadius, mPadding + mSchemeBaseLine, mTextPaint);
}
if (calendar.isWeekend() && calendar.isCurrentMonth()) {
mCurMonthTextPaint.setColor(0xFF489dff);
mCurMonthLunarTextPaint.setColor(0xFF489dff);
mSchemeTextPaint.setColor(0xFF489dff);
mSchemeLunarTextPaint.setColor(0xFF489dff);
mOtherMonthLunarTextPaint.setColor(0xFF489dff);
mOtherMonthTextPaint.setColor(0xFF489dff);
} else {
mCurMonthTextPaint.setColor(0xff333333);
mCurMonthLunarTextPaint.setColor(0xffCFCFCF);
mSchemeTextPaint.setColor(0xff333333);
mSchemeLunarTextPaint.setColor(0xffCFCFCF);
mOtherMonthTextPaint.setColor(0xFFe1e1e1);
mOtherMonthLunarTextPaint.setColor(0xFFe1e1e1);
}
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
mSelectTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSelectedLunarTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
!TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint : mSchemeLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
!TextUtils.isEmpty(calendar.getSolarTerm()) ? mSolarTermTextPaint :
calendar.isCurrentMonth() ?
mCurMonthLunarTextPaint : mOtherMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
@@ -0,0 +1,86 @@
package com.haibin.calendarviewproject.multi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MultiMonthView;
/**
* 高仿魅族日历布局
* Created by huanghaibin on 2017/11/15.
*/
public class CustomMultiMonthView extends MultiMonthView {
private int mRadius;
public CustomMultiMonthView(Context context) {
super(context);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
mSchemePaint.setStyle(Paint.Style.STROKE);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
if (isSelectedPre) {
if (isSelectedNext) {
canvas.drawRect(x, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
} else {//最后一个the last
canvas.drawRect(x, cy - mRadius, cx, cy + mRadius, mSelectedPaint);
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
}
} else {
if(isSelectedNext){
canvas.drawRect(cx, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
}
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
//
}
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine + y;
int cx = x + mItemWidth / 2;
boolean isInRange = isInRange(calendar);
boolean isEnable = !onCalendarIntercept(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mSchemeTextPaint : mOtherMonthTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mCurMonthTextPaint : mOtherMonthTextPaint);
}
}
}
@@ -0,0 +1,84 @@
package com.haibin.calendarviewproject.multi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MultiWeekView;
/**
* 魅族周视图
* Created by huanghaibin on 2017/11/29.
*/
public class CustomMultiWeekView extends MultiWeekView {
private int mRadius;
public CustomMultiWeekView(Context context) {
super(context);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
mSchemePaint.setStyle(Paint.Style.STROKE);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme,
boolean isSelectedPre, boolean isSelectedNext) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
if (isSelectedPre) {
if (isSelectedNext) {
canvas.drawRect(x, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
} else {//最后一个the last
canvas.drawRect(x, cy - mRadius, cx, cy + mRadius, mSelectedPaint);
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
}
} else {
if (isSelectedNext) {
canvas.drawRect(cx, cy - mRadius, x + mItemWidth, cy + mRadius, mSelectedPaint);
}
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
}
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, boolean isSelected) {
int cx = x + mItemWidth / 2;
int cy = mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine;
int cx = x + mItemWidth / 2;
boolean isInRange = isInRange(calendar);
boolean isEnable = !onCalendarIntercept(calendar);
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mSchemeTextPaint : mOtherMonthTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() && isInRange && isEnable? mCurMonthTextPaint : mOtherMonthTextPaint);
}
}
}
@@ -0,0 +1,246 @@
package com.haibin.calendarviewproject.multi;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
import java.util.HashMap;
import java.util.Map;
public class MultiActivity extends BaseActivity implements
CalendarView.OnCalendarMultiSelectListener,
CalendarView.OnCalendarInterceptListener,
CalendarView.OnYearChangeListener,
CalendarView.OnMonthChangeListener,
CalendarView.OnCalendarSelectListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
GroupRecyclerView mRecyclerView;
public static void show(Context context) {
context.startActivity(new Intent(context, MultiActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_multi;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
//mCalendarView.setMaxMultiSelectSize(9);
// Calendar calendar = new Calendar();
// calendar.setYear(mCalendarView.getCurYear());
// calendar.setMonth(mCalendarView.getCurMonth());
// calendar.setDay(mCalendarView.getCurDay());
// mCalendarView.putMultiSelect(calendar);
// mCalendarView.removeMultiSelect(calendar);
// mCalendarView.getMultiSelectCalendars();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarMultiSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mCalendarView.setOnCalendarSelectListener(this);
//设置日期拦截事件当前有效
mCalendarView.setOnCalendarInterceptListener(this);
mCalendarView.setOnMonthChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
findViewById(R.id.iv_clear).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.clearMultiSelect();
}
});
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(this));
mRecyclerView.notifyDataSetChanged();
}
@Override
public void onClick(View v) {
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
calendar.addScheme(new Calendar.Scheme());
calendar.addScheme(0xFF008800, "");
calendar.addScheme(0xFF008800, "");
return calendar;
}
@Override
public void onCalendarMultiSelectOutOfRange(Calendar calendar) {
Log.e("OutOfRange", "OutOfRange" + calendar);
}
@Override
public void onMultiSelectOutOfSize(Calendar calendar, int maxSize) {
Toast.makeText(this, "超过最大选择数量 " + maxSize, Toast.LENGTH_SHORT).show();
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarMultiSelect(Calendar calendar, int curSize, int maxSize) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
Log.e("onDateSelected", " -- " + calendar.getYear() +
" -- " + calendar.getMonth() +
" -- " + calendar.getDay() +
" -- " + " -- " + calendar.getScheme());
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
@Override
public void onMonthChange(int year, int month) {
Log.e("onMonthChange", " -- " + year + " -- " + month);
}
/**
* 屏蔽某些不可点击的日期可根据自己的业务自行修改
* calendar > 2018年1月1日 && calendar <= 2020年12月31日
*
* @param calendar calendar
* @return 是否屏蔽某些不可点击的日期MonthView和WeekView有类似的API可调用
*/
@Override
public boolean onCalendarIntercept(Calendar calendar) {
//Log.e("onCalendarIntercept", calendar.toString());
int day = calendar.getDay();
// return day == 1 || day == 3 || day == 6 || day == 11 ||
// day == 12 || day == 15 || day == 20 || day == 26;
// return calendar.hasScheme();
return calendar.getYear()<= mCalendarView.getCurYear() &&
calendar.getMonth() <= mCalendarView.getCurMonth() &&
calendar.getDay() < mCalendarView.getCurDay();
}
@Override
public void onCalendarInterceptClick(Calendar calendar, boolean isClick) {
Toast.makeText(this,
calendar.toString() + (isClick ? "拦截不可点击" : "拦截设定为无效日期"),
Toast.LENGTH_SHORT).show();
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
Log.e("onDateSelected", " -- " + calendar.getYear() +
" -- " + calendar.getMonth() +
" -- " + calendar.getDay() +
" -- " + isClick + " -- " + calendar.getScheme());
}
}
@@ -0,0 +1,43 @@
package com.haibin.calendarviewproject.pager;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarviewproject.base.fragment.FragmentAdapter;
/**
* 如果嵌套各种View出现事件冲突可以实现这个方法即可
*/
public class CalendarLinearLayout extends LinearLayout implements CalendarLayout.CalendarScrollView {
private FragmentAdapter mAdapter;
public CalendarLinearLayout(Context context) {
super(context);
}
public CalendarLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
/**
* 如果你想让下拉无效return false
*
* @return isScrollToTop
*/
@Override
public boolean isScrollToTop() {
if(mAdapter == null){
if (getChildCount() > 1 && getChildAt(1) instanceof ViewPager) {
ViewPager viewPager = (ViewPager) getChildAt(1);
mAdapter = (FragmentAdapter) viewPager.getAdapter();
}
}
return mAdapter != null && ((PagerFragment) mAdapter.getCurFragment()).isScrollTop();
}
}
@@ -0,0 +1,43 @@
package com.haibin.calendarviewproject.pager;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.fragment.BaseFragment;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
public class PagerFragment extends BaseFragment {
private GroupRecyclerView mRecyclerView;
static PagerFragment newInstance() {
return new PagerFragment();
}
@Override
protected int getLayoutId() {
return R.layout.fragment_pager;
}
@Override
protected void initView() {
mRecyclerView = mRootView.findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(mContext));
mRecyclerView.notifyDataSetChanged();
}
@Override
protected void initData() {
}
boolean isScrollTop() {
return mRecyclerView != null && mRecyclerView.computeVerticalScrollOffset() == 0;
}
}
@@ -0,0 +1,191 @@
package com.haibin.calendarviewproject.pager;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.google.android.material.tabs.TabLayout;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.base.fragment.FragmentAdapter;
import com.haibin.calendarviewproject.colorful.ColorfulActivity;
import com.haibin.calendarviewproject.index.IndexActivity;
import com.haibin.calendarviewproject.meizu.MeiZuActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ViewPagerActivity extends BaseActivity implements
View.OnClickListener,
CalendarView.OnCalendarSelectListener,
CalendarView.OnYearChangeListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
public static void show(Context context) {
context.startActivity(new Intent(context, ViewPagerActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_view_pager;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
ViewPager viewPager = findViewById(R.id.viewPager);
TabLayout tabLayout = findViewById(R.id.tabLayout);
FragmentAdapter adapter = new FragmentAdapter(getSupportFragmentManager());
adapter.reset(new String[]{"热门", "头条", "时尚"});
List<Fragment> fragments = new ArrayList<>();
fragments.add(PagerFragment.newInstance());
fragments.add(PagerFragment.newInstance());
fragments.add(PagerFragment.newInstance());
adapter.reset(fragments);
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, ""));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, ""));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, ""));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, ""));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, ""));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, ""));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, ""));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, ""));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
calendar.addScheme(new Calendar.Scheme());
calendar.addScheme(0xFF008800, "");
calendar.addScheme(0xFF008800, "");
return calendar;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
MeiZuActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
}
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
}
}
@@ -0,0 +1,185 @@
package com.haibin.calendarviewproject.progress;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.CalendarLayout;
import com.haibin.calendarview.CalendarView;
import com.haibin.calendarviewproject.Article;
import com.haibin.calendarviewproject.ArticleAdapter;
import com.haibin.calendarviewproject.R;
import com.haibin.calendarviewproject.base.activity.BaseActivity;
import com.haibin.calendarviewproject.colorful.ColorfulActivity;
import com.haibin.calendarviewproject.group.GroupItemDecoration;
import com.haibin.calendarviewproject.group.GroupRecyclerView;
import com.haibin.calendarviewproject.index.IndexActivity;
import com.haibin.calendarviewproject.simple.SimpleActivity;
import java.util.HashMap;
import java.util.Map;
public class ProgressActivity extends BaseActivity implements
CalendarView.OnCalendarSelectListener,
CalendarView.OnYearChangeListener,
View.OnClickListener {
TextView mTextMonthDay;
TextView mTextYear;
TextView mTextLunar;
TextView mTextCurrentDay;
CalendarView mCalendarView;
RelativeLayout mRelativeTool;
private int mYear;
CalendarLayout mCalendarLayout;
GroupRecyclerView mRecyclerView;
public static void show(Context context) {
context.startActivity(new Intent(context, ProgressActivity.class));
}
@Override
protected int getLayoutId() {
return R.layout.activity_progress;
}
@SuppressLint("SetTextI18n")
@Override
protected void initView() {
setStatusBarDarkMode();
mTextMonthDay = findViewById(R.id.tv_month_day);
mTextYear = findViewById(R.id.tv_year);
mTextLunar = findViewById(R.id.tv_lunar);
mRelativeTool = findViewById(R.id.rl_tool);
mCalendarView = findViewById(R.id.calendarView);
mTextCurrentDay = findViewById(R.id.tv_current_day);
mTextMonthDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mCalendarLayout.isExpand()) {
mCalendarLayout.expand();
return;
}
mCalendarView.showYearSelectLayout(mYear);
mTextLunar.setVisibility(View.GONE);
mTextYear.setVisibility(View.GONE);
mTextMonthDay.setText(String.valueOf(mYear));
}
});
findViewById(R.id.fl_current).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCalendarView.scrollToCurrent();
}
});
mCalendarLayout = findViewById(R.id.calendarLayout);
mCalendarView.setOnCalendarSelectListener(this);
mCalendarView.setOnYearChangeListener(this);
mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
mYear = mCalendarView.getCurYear();
mTextMonthDay.setText(mCalendarView.getCurMonth() + "" + mCalendarView.getCurDay() + "");
mTextLunar.setText("今日");
mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
}
@Override
protected void initData() {
int year = mCalendarView.getCurYear();
int month = mCalendarView.getCurMonth();
Map<String, Calendar> map = new HashMap<>();
map.put(getSchemeCalendar(year, month, 3, 0xFF40db25, "20").toString(),
getSchemeCalendar(year, month, 3, 0xFF40db25, "20"));
map.put(getSchemeCalendar(year, month, 6, 0xFFe69138, "33").toString(),
getSchemeCalendar(year, month, 6, 0xFFe69138, "33"));
map.put(getSchemeCalendar(year, month, 9, 0xFFdf1356, "25").toString(),
getSchemeCalendar(year, month, 9, 0xFFdf1356, "25"));
map.put(getSchemeCalendar(year, month, 13, 0xFFedc56d, "50").toString(),
getSchemeCalendar(year, month, 13, 0xFFedc56d, "50"));
map.put(getSchemeCalendar(year, month, 14, 0xFFedc56d, "80").toString(),
getSchemeCalendar(year, month, 14, 0xFFedc56d, "80"));
map.put(getSchemeCalendar(year, month, 15, 0xFFaacc44, "20").toString(),
getSchemeCalendar(year, month, 15, 0xFFaacc44, "20"));
map.put(getSchemeCalendar(year, month, 18, 0xFFbc13f0, "70").toString(),
getSchemeCalendar(year, month, 18, 0xFFbc13f0, "70"));
map.put(getSchemeCalendar(year, month, 25, 0xFF13acf0, "36").toString(),
getSchemeCalendar(year, month, 25, 0xFF13acf0, "36"));
map.put(getSchemeCalendar(year, month, 27, 0xFF13acf0, "95").toString(),
getSchemeCalendar(year, month, 27, 0xFF13acf0, "95"));
//此方法在巨大的数据量上不影响遍历性能推荐使用
mCalendarView.setSchemeDate(map);
mRecyclerView = findViewById(R.id.recyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new GroupItemDecoration<String, Article>());
mRecyclerView.setAdapter(new ArticleAdapter(this));
mRecyclerView.notifyDataSetChanged();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ll_flyme:
ProgressActivity.show(this);
break;
case R.id.ll_simple:
SimpleActivity.show(this);
break;
case R.id.ll_colorful:
ColorfulActivity.show(this);
break;
case R.id.ll_index:
IndexActivity.show(this);
break;
}
}
private Calendar getSchemeCalendar(int year, int month, int day, int color, String text) {
Calendar calendar = new Calendar();
calendar.setYear(year);
calendar.setMonth(month);
calendar.setDay(day);
calendar.setSchemeColor(color);//如果单独标记颜色则会使用这个颜色
calendar.setScheme(text);
return calendar;
}
@Override
public void onCalendarOutOfRange(Calendar calendar) {
}
@SuppressLint("SetTextI18n")
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
mTextLunar.setVisibility(View.VISIBLE);
mTextYear.setVisibility(View.VISIBLE);
mTextMonthDay.setText(calendar.getMonth() + "" + calendar.getDay() + "");
mTextYear.setText(String.valueOf(calendar.getYear()));
mTextLunar.setText(calendar.getLunar());
mYear = calendar.getYear();
}
@Override
public void onYearChange(int year) {
mTextMonthDay.setText(String.valueOf(year));
}
}
@@ -0,0 +1,110 @@
package com.haibin.calendarviewproject.progress;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MonthView;
/**
* 精美进度风格
* Created by huanghaibin on 2018/2/8.
*/
public class ProgressMonthView extends MonthView {
private Paint mProgressPaint = new Paint();
private Paint mNoneProgressPaint = new Paint();
private int mRadius;
public ProgressMonthView(Context context) {
super(context);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeWidth(dipToPx(context, 2.2f));
mProgressPaint.setColor(0xBBf54a00);
mNoneProgressPaint.setAntiAlias(true);
mNoneProgressPaint.setStyle(Paint.Style.STROKE);
mNoneProgressPaint.setStrokeWidth(dipToPx(context, 2.2f));
mNoneProgressPaint.setColor(0x90CfCfCf);
}
@Override
protected void onPreviewHook() {
mRadius = Math.min(mItemWidth, mItemHeight) / 11 * 4;
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
return false;
}
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
int cx = x + mItemWidth / 2;
int cy = y + mItemHeight / 2;
int angle = getAngle(Integer.parseInt(calendar.getScheme()));
RectF progressRectF = new RectF(cx - mRadius, cy - mRadius, cx + mRadius, cy + mRadius);
canvas.drawArc(progressRectF, -90, angle, false, mProgressPaint);
RectF noneRectF = new RectF(cx - mRadius, cy - mRadius, cx + mRadius, cy + mRadius);
canvas.drawArc(noneRectF, angle - 90, 360 - angle, false, mNoneProgressPaint);
}
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
float baselineY = mTextBaseLine + y;
int cx = x + mItemWidth / 2;
if (isSelected) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
mSelectTextPaint);
} else if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()),
cx,
baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, baselineY,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
}
}
/**
* 获取角度
*
* @param progress 进度
* @return 获取角度
*/
private static int getAngle(int progress) {
return (int) (progress * 3.6);
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}

Some files were not shown because too many files have changed in this diff Show More