SuperCalendar是一个日历控件,在使用它时,如果
calendarAdapter.setMarkData(markData);
被调用了两次就出现问题了,会导致第二次设置的map覆盖掉第一次设置的Map
问题
它给的例子是这样的:
private void initMarkData() {
HashMap<String,String> markData=new HashMap<>();
//1的时候是灰色,0的时候是亮色
markData.put("2018-6-1", "1");
markData.put("2018-6-2", "1");
markData.put("2018-6-3", "0");
markData.put("2018-6-4", "0");
markData.put("2018-7-5", "0");
markData.put("2018-7-6", "1");
markData.put("2018-7-7", "1");
calendarAdapter.setMarkData(markData);
}
加入我们有这个场景,联网获取每一个月的标记数据,然后标记上,那么这个方法的调用肯定不止一次,所以在请求网络结束后需要调用以下方法来更新标记:
(不要调用notifyDataChanged()
,这一点文档有误,否则会报空指针)
//1的时候是灰色,0的时候是亮色
HashMap<String,String> markData=new HashMap<>();
markData.put("2018-6-9", "0");
markData.put("2018-6-10", "0");
markData.put("2018-7-10", "0");
markData.put("2018-7-11", "0");
markData.put("2018-7-12", "1");
calendarAdapter.setMarkData(markData);
}
等等,运行后,你会发现第一次的数据没有了,为什么呢?
只有一个原因,那就是我们第二次设置markData后把第一次覆盖掉了,也就是说第二次设置的这个Map引用覆盖掉了第一次设置的Map引用。
通过代码跟进,发现:CalendarViewAdapter.java
public void setMarkData(HashMap<String, String> markData) {
Utils.setMarkData(markData);
}
继续跟进:Utils.java
public static void setMarkData(HashMap<String, String> data) {
markData = data;
}
果然,它是直接修改了这个引用,所以第二次肯定覆盖掉第一次设置的值
解决办法
方法1:本来我是想看一下它有没有getMarkData()
这类的方法,如果有的话我们只需要将新的Map追加到旧的Map中即可,未果
方法2:我们的本意是每次添加markData
时不修改HashMap
的引用,那么只要维护一个HashMap
即可,不管第几次添加mark
,都添加到该HashMap
中
例如:
- 设置一个全局的
HashMap
public HashMap<String, String> markData=new HashMap<>();
- 然后设置
markData
即可
/**
* 初始化标记数据
*/
private void initMarkData() {
//1的时候是灰色,0的时候是亮色
markData.put("2018-6-1", "1");
markData.put("2018-6-2", "1");
markData.put("2018-6-3", "0");
markData.put("2018-6-4", "0");
markData.put("2018-7-5", "0");
markData.put("2018-7-6", "1");
markData.put("2018-7-7", "1");
calendarAdapter.setMarkData(markData);
}
/**
* 刘壮飞
*
* 这里模拟的是第二次setMarkData(markData)的情景
*
* 我们维护一个Map,注意不要修改该Map的引用
* 可以使用clear(),不要用markData=new HashMap<>();
*/
public void initMarkDataAfter(){
//1的时候是灰色,0的时候是亮色
markData.put("2018-6-9", "0");
markData.put("2018-6-10", "0");
markData.put("2018-7-10", "0");
markData.put("2018-7-11", "0");
markData.put("2018-7-12", "1");
calendarAdapter.setMarkData(markData);
}
完整的代码
大功告成了!!!
以下是MainActivity的完整代码,其他代码与项目中给的example完全一致,此代码中只有添加了刘壮飞
标记的才是我添加的部分,已在上文列出
package com.zhuangfei.calenderdemo;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.ldf.calendar.Utils;
import com.ldf.calendar.component.CalendarAttr;
import com.ldf.calendar.view.MonthPager;
import com.ldf.calendar.interf.OnSelectDateListener;
import com.ldf.calendar.component.CalendarViewAdapter;
import com.ldf.calendar.model.CalendarDate;
import com.ldf.calendar.view.Calendar;
import com.zhuangfei.calenderdemo.CustomDayView;
import com.zhuangfei.calenderdemo.R;
import com.zhuangfei.calenderdemo.ThemeDayView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ldf on 16/11/4.
*/
@SuppressLint("SetTextI18n")
public class MainActivity extends AppCompatActivity {
TextView tvYear;
TextView tvMonth;
TextView backToday;
CoordinatorLayout content;
MonthPager monthPager;
RecyclerView rvToDoList;
TextView scrollSwitch;
TextView themeSwitch;
TextView nextMonthBtn;
TextView lastMonthBtn;
private ArrayList<Calendar> currentCalendars = new ArrayList<>();
private CalendarViewAdapter calendarAdapter;
private OnSelectDateListener onSelectDateListener;
private int mCurrentPage = MonthPager.CURRENT_DAY_INDEX;
private Context context;
private CalendarDate currentDate;
private boolean initiated = false;
/**
* 刘壮飞
*/
public HashMap<String, String> markData=new HashMap<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
content = (CoordinatorLayout) findViewById(R.id.content);
monthPager = (MonthPager) findViewById(R.id.calendar_view);
//此处强行setViewHeight,毕竟你知道你的日历牌的高度
monthPager.setViewHeight(Utils.dpi2px(context, 270));
tvYear = (TextView) findViewById(R.id.show_year_view);
tvMonth = (TextView) findViewById(R.id.show_month_view);
backToday = (TextView) findViewById(R.id.back_today_button);
scrollSwitch = (TextView) findViewById(R.id.scroll_switch);
themeSwitch = (TextView) findViewById(R.id.theme_switch);
nextMonthBtn = (TextView) findViewById(R.id.next_month);
lastMonthBtn = (TextView) findViewById(R.id.last_month);
rvToDoList = (RecyclerView) findViewById(R.id.list);
rvToDoList.setHasFixedSize(true);
//这里用线性显示 类似于listview
rvToDoList.setLayoutManager(new LinearLayoutManager(this));
rvToDoList.setAdapter(new ExampleAdapter(this));
initCurrentDate();
initCalendarView();
initToolbarClickListener();
Log.e("ldf","OnCreated");
initMarkDataAfter();
}
/**
* onWindowFocusChanged回调时,将当前月的种子日期修改为今天
*
* @return void
*/
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && !initiated) {
refreshMonthPager();
initiated = true;
}
}
/*
* 如果你想以周模式启动你的日历,请在onResume是调用
* Utils.scrollTo(content, rvToDoList, monthPager.getCellHeight(), 200);
* calendarAdapter.switchToWeek(monthPager.getRowIndex());
* */
@Override
protected void onResume() {
super.onResume();
}
/**
* 初始化对应功能的listener
*
* @return void
*/
private void initToolbarClickListener() {
backToday.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onClickBackToDayBtn();
}
});
scrollSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (calendarAdapter.getCalendarType() == CalendarAttr.CalendarType.WEEK) {
Utils.scrollTo(content, rvToDoList, monthPager.getViewHeight(), 200);
calendarAdapter.switchToMonth();
} else {
Utils.scrollTo(content, rvToDoList, monthPager.getCellHeight(), 200);
calendarAdapter.switchToWeek(monthPager.getRowIndex());
}
}
});
themeSwitch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
refreshSelectBackground();
}
});
nextMonthBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
monthPager.setCurrentItem(monthPager.getCurrentPosition() + 1);
}
});
lastMonthBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
monthPager.setCurrentItem(monthPager.getCurrentPosition() - 1);
}
});
}
/**
* 初始化currentDate
*
* @return void
*/
private void initCurrentDate() {
currentDate = new CalendarDate();
tvYear.setText(currentDate.getYear() + "年");
tvMonth.setText(currentDate.getMonth() + "");
}
/**
* 初始化CustomDayView,并作为CalendarViewAdapter的参数传入
*/
private void initCalendarView() {
initListener();
CustomDayView customDayView = new CustomDayView(context, R.layout.custom_day);
calendarAdapter = new CalendarViewAdapter(
context,
onSelectDateListener,
CalendarAttr.CalendarType.MONTH,
CalendarAttr.WeekArrayType.Monday,
customDayView);
calendarAdapter.setOnCalendarTypeChangedListener(new CalendarViewAdapter.OnCalendarTypeChanged() {
@Override
public void onCalendarTypeChanged(CalendarAttr.CalendarType type) {
rvToDoList.scrollToPosition(0);
}
});
initMarkData();
initMonthPager();
}
/**
* 初始化标记数据,HashMap的形式,可自定义
* 如果存在异步的话,在使用setMarkData之后调用 calendarAdapter.notifyDataChanged();
*/
private void initMarkData() {
HashMap<String,String> markData=new HashMap<>();
//1的时候是灰色,0的时候是亮色
markData.put("2018-6-1", "1");
markData.put("2018-6-2", "1");
markData.put("2018-6-3", "0");
markData.put("2018-6-4", "0");
markData.put("2018-7-5", "0");
markData.put("2018-7-6", "1");
markData.put("2018-7-7", "1");
calendarAdapter.setMarkData(markData);
}
/**
* 刘壮飞
*
* 这里模拟的是第二次setMarkData(markData)的情景
*
* 我们维护一个Map,注意不要修改该Map的引用
* 可以使用clear(),不要用markData=new HashMap<>();
*/
public void initMarkDataAfter(){
//1的时候是灰色,0的时候是亮色
markData.put("2018-6-9", "0");
markData.put("2018-6-10", "0");
markData.put("2018-7-10", "0");
markData.put("2018-7-11", "0");
markData.put("2018-7-12", "1");
calendarAdapter.setMarkData(markData);
}
private void initListener() {
onSelectDateListener = new OnSelectDateListener() {
@Override
public void onSelectDate(CalendarDate date) {
refreshClickDate(date);
}
@Override
public void onSelectOtherMonth(int offset) {
//偏移量 -1表示刷新成上一个月数据 , 1表示刷新成下一个月数据
monthPager.selectOtherMonth(offset);
}
};
}
private void refreshClickDate(CalendarDate date) {
currentDate = date;
tvYear.setText(date.getYear() + "年");
tvMonth.setText(date.getMonth() + "");
}
/**
* 初始化monthPager,MonthPager继承自ViewPager
*
* @return void
*/
private void initMonthPager() {
monthPager.setAdapter(calendarAdapter);
monthPager.setCurrentItem(MonthPager.CURRENT_DAY_INDEX);
monthPager.setPageTransformer(false, new ViewPager.PageTransformer() {
@Override
public void transformPage(View page, float position) {
position = (float) Math.sqrt(1 - Math.abs(position));
page.setAlpha(position);
}
});
monthPager.addOnPageChangeListener(new MonthPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mCurrentPage = position;
currentCalendars = calendarAdapter.getPagers();
if (currentCalendars.get(position % currentCalendars.size()) != null) {
CalendarDate date = currentCalendars.get(position % currentCalendars.size()).getSeedDate();
currentDate = date;
tvYear.setText(date.getYear() + "年");
tvMonth.setText(date.getMonth() + "");
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
public void onClickBackToDayBtn() {
refreshMonthPager();
}
private void refreshMonthPager() {
CalendarDate today = new CalendarDate();
calendarAdapter.notifyDataChanged(today);
tvYear.setText(today.getYear() + "年");
tvMonth.setText(today.getMonth() + "");
}
private void refreshSelectBackground() {
ThemeDayView themeDayView = new ThemeDayView(context, R.layout.custom_day_focus);
calendarAdapter.setCustomDayRenderer(themeDayView);
calendarAdapter.notifyDataSetChanged();
calendarAdapter.notifyDataChanged(new CalendarDate());
}
}