Android自定义日历控件(继承系统控件实现)
主要步骤
- 编写布局
- 继承LinearLayout设置子控件
- 设置数据
- 继承TextView实现有圆圈背景的TextView
- 添加Attribute
- 添加长按事件
1.编写布局
2.继承LinearLayout设置子控件
public class CalendarView extends LinearLayout { private ImageView btnPre; private ImageView btnNext; private TextView txtData; private GridView gridView; private Calendar calendar = Calendar.getInstance(); private String displayFormat; public NewViewListener viewListener; public void setViewListener(NewViewListener viewListener) { this.viewListener = viewListener; } public CalendarView(Context context) { super(context); } public CalendarView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initControl(context, attrs); } public CalendarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initControl(context, attrs); } private void initControl(Context context, AttributeSet attributeSet) { bindControl(context); bindControlEvent(); setAttribute(attributeSet); renderCalender(); } private void bindControl(Context context) { LayoutInflater.from(context).inflate(R.layout.new_view, this); btnNext = (ImageView) findViewById(R.id.btn_next); btnPre = (ImageView) findViewById(R.id.btn_pre); txtData = (TextView) findViewById(R.id.txtData); gridView = (GridView) findViewById(R.id.grid); } private void bindControlEvent() { btnNext.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { calendar.add(Calendar.MONTH, +1); renderCalender(); } }); btnPre.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { calendar.add(Calendar.MONTH, -1); renderCalender(); } }); } }
3.设置数据
private void renderCalender() { //返回"月+日"格式的数据 SimpleDateFormat sdf = new SimpleDateFormat(displayFormat, Locale.CHINA); txtData.setText(sdf.format(calendar.getTime())); ArrayListcells = new ArrayList<>(); Calendar calendar2 = (Calendar) this.calendar.clone(); //设置月的第一天为1 calendar2.set(Calendar.DAY_OF_MONTH, 1); //获取当前周数的前一天 int prevDays = calendar2.get(Calendar.DAY_OF_WEEK) - 1; //运算日历加上加前一周 calendar2.add(Calendar.DAY_OF_MONTH, -prevDays); int maxCellCount = 6 * 7; //将日历里的日期数据添加到ArrayList while (cells.size() < maxCellCount) { cells.add(calendar2.getTime()); calendar2.add(Calendar.DAY_OF_MONTH, 1); } gridView.setAdapter(new MyAdapter(getContext(), cells)); gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { if (viewListener == null) { return false; } else { viewListener.onItemLongPress((Date) parent.getItemAtPosition(position)); return true; } } }); } private class MyAdapter extends ArrayAdapter { LayoutInflater layoutInflater; MyAdapter(@NonNull Context context, ArrayList dates) { super(context, R.layout.calendar_text_day, dates); layoutInflater = LayoutInflater.from(context); } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { Date date = getItem(position); if (convertView == null) { convertView = layoutInflater.inflate(R.layout.calendar_text_day, parent, false); } int day = date.getDate(); ((CalendarTextView) convertView).setText(String.valueOf(day)); Date now = new Date(); boolean isSameMonth = false; if (date.getMonth() == now.getMonth()) { isSameMonth = true; } if (isSameMonth) { ((CalendarTextView) convertView).setTextColor(Color.DKGRAY); } if (now.getDate() == date.getDate() && now.getMonth() == date.getMonth() && now.getYear() == date.getYear()) { ((CalendarTextView) convertView).setNow(true); } return convertView; } }
4. 圆圈背景TextView
public class CalendarTextView extends AppCompatTextView { private Paint paint; private boolean isNow = false; public void setNow(boolean now) { isNow = now; } public CalendarTextView(Context context) { super(context); } public CalendarTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initControl(); } public CalendarTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initControl(); } private void initControl() { paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.RED); paint.setStrokeWidth(2); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (isNow) { canvas.translate(getWidth() / 2, getHeight() / 2); canvas.drawCircle(0, 0, getWidth() / 2, paint); setTextColor(Color.RED); } }}
5.添加Attribute
添加attrs文件
将Arrtibute参数设置到控件
private void setAttribute(AttributeSet attributeSet) { TypedArray ta = getContext().obtainStyledAttributes(attributeSet, R.styleable.CalendarView); try { displayFormat = ta.getString(R.styleable.CalendarView_dateFormat); if (displayFormat == null) { displayFormat = "MMM yyy"; } } finally { ta.recycle(); } }
在布局中加入命名控件引入
<com.example.jiyang.newview.CalendarView xmlns:CalendarView="http://schemas.android.com/apk/res/com.example.jiyang.newview" android:id="@+id/newView" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" CalendarView:dateFormat="MMMM yyyy" />
6.添加长按事件
定义长按接口
public interface NewViewListener { void onItemLongPress(Date day); }
- CalenderView中调用
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { if (viewListener == null) { return false; } else { viewListener.onItemLongPress((Date) parent.getItemAtPosition(position)); return true; } } });
Activity中实现接口方法
@Override public void onItemLongPress(Date day) { DateFormat df = SimpleDateFormat.getDateInstance(); Toast.makeText(this, df.format(day), Toast.LENGTH_SHORT).show(); }
总结
Attribute的使用
- 定义attrs文件
- 注意命名空间。自定义View不能使用
app:
,而要使用xmlns:
自定义一个命名空间 - TypedArray放入
try{}finaly{}
中,要在finally
中释放TypedArraytypedArray.recycle()
通过继承布局实现自定义View时,加载布局
需要LayoutInflater.from(context).inflate(R.layout.new_view, this);
不能LayoutInflater.from(context).inflate(R.layout.new_view, this,false);