package com.example.lshan.canvascalendar; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; public class CanvasCalendar extends View implements View.OnTouchListener,GestureDetector.OnGestureListener{ private float width = 0f,radius = 0f; private Paint circlep,textp,todayp; private int monthday = 0; private int year = 0,month = 0; private Map<String,String> date = new HashMap<String,String>(); private SelectCalendarListener selectCalendarListener; private FlingCalendarListener flingCalendarListener; private Date curDate = new Date(); private Calendar mcalendar; private GestureDetector gd = new GestureDetector(this); private float upx = 0f, upy = 0f; private float downx =0f,downy = 0f; public CanvasCalendar(Context context) { super(context); initDate(curDate); } public CanvasCalendar(Context context, AttributeSet attrs) { super(context, attrs); initDate(curDate); } public CanvasCalendar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initDate(curDate); } public void setDate(Date mdate){ this.curDate = mdate; initDate(mdate); } public void setWidth(float width){ this.width = width; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawCircle(canvas); setMonth(mcalendar.get(Calendar.YEAR), mcalendar.get(Calendar.MONTH) + 1); drawText(canvas); setOnTouchListener(this); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().widthPixels * 6 / 7); } public void drawCircle(Canvas canvas){ for(int x = 0; x < 7;x++){ for(int y = 0; y < 6; y++){ canvas.drawCircle((x+1/2f)*width/7f,(y+1/2f)*width/7f,radius,circlep); } } invalidate(); } public void drawText(Canvas canvas){ //選中日期 mcalendar.setTime(curDate); int today = mcalendar.get(Calendar.DAY_OF_MONTH); int todaymonth = mcalendar.get(Calendar.MONTH); int todayyear = mcalendar.get(Calendar.YEAR); int selectx = mcalendar.get(Calendar.DAY_OF_WEEK) - 1; int selecty = mcalendar.get(Calendar.WEEK_OF_MONTH)-1; //當前日期 Date tdate = new Date(); mcalendar.setTime(tdate); int today2 = mcalendar.get(Calendar.DAY_OF_MONTH); int today2month = mcalendar.get(Calendar.MONTH); int today2year = mcalendar.get(Calendar.YEAR); //當月日期 for(int i = 1; i <= monthday; i++){ mcalendar.set(year, month-1, i); int x = mcalendar.get(Calendar.DAY_OF_WEEK) - 1; int y = mcalendar.get(Calendar.WEEK_OF_MONTH)-1; canvas.drawText("" + i, (x + 1 / 2f) * width / 7f - textp.measureText("" + i) / 2f, (y + 1 / 2f) * width / 7f + textp.measureText("" + i) / 2f, textp); if(i == today){ canvas.drawCircle((selectx+1/2f)*width/7f,(selecty+1/2f)*width/7f,radius,textp); canvas.drawText(""+today,(selectx+1/2f)*width/7f - circlep.measureText(""+i)/2f,(selecty+1/2f)*width/7f + circlep.measureText(""+i)/2f,circlep); }else if (i == today2 && today2month == todaymonth && today2year == todayyear){ canvas.drawCircle((x+1/2f)*width/7f,(y+1/2f)*width/7f,radius,todayp); } else{ canvas.drawText(""+i,(x+1/2f)*width/7f - textp.measureText(""+i)/2f,(y+1/2f)*width/7f + textp.measureText(""+i)/2f,textp); } date.put(""+x+y,month+","+i); } //上個月日期 mcalendar.set(year,month-1,1); int lx = mcalendar.get(Calendar.DAY_OF_WEEK) - 2; int mons = getMonthday(month - 1); for(int j = lx ; j >= 0 ;j--,mons--){ canvas.drawText(""+mons,(j+1/2f)*width/7f - textp.measureText(""+mons)/2f,(1/2f)*width/7f + textp.measureText(""+mons)/2f,textp); date.put("" + j + 0, (month - 1) + "," + mons); } //下個月日期 mcalendar.set(year, month - 1, monthday); int nx = mcalendar.get(Calendar.DAY_OF_WEEK)+1; int ny = mcalendar.get(Calendar.WEEK_OF_MONTH); int day = 1; for(int ni = ny; ni < 7 ; ni++){ for(int nj = nx; nj <8;nj++,day++){ canvas.drawText(""+day,(nj - 1 + 1/2f)*width/7f - textp.measureText(""+day)/2f,(ni - 1 + 1/2f)*width/7f + textp.measureText(""+day)/2f,textp); date.put("" + (nj - 1) + (ni - 1), (month + 1) + "," + day); } nx = 1; } invalidate(); } public void setMonth(int year,int mon){ this.year = year; this.month = mon; monthday = getMonthday(mon); } public Date lastMonth() { mcalendar.setTime(curDate); mcalendar.add(Calendar.MONTH, -1); curDate = mcalendar.getTime(); invalidate(); return curDate; } public Date nextMonth() { mcalendar.setTime(curDate); mcalendar.add(Calendar.MONTH, 1); curDate = mcalendar.getTime(); invalidate(); return curDate; } public int getMonthday(int mon){ int days = 0; if(mon == 1 || mon == 3 || mon == 5 || mon == 7 || mon == 8 || mon == 10 || mon == 12){ days = 31; }else if(mon == 2){ if((year/4==0&&year/100!=0)|| year/400 == 0){ days = 29; }else{ days = 28; } }else{ days = 30; } return days; } @Override public boolean onTouch(View v, MotionEvent event) { float x = event.getX(); float y = event.getY(); boolean fling = true; switch(event.getAction()){ case MotionEvent.ACTION_DOWN: downx = event.getX(); downy = event.getY(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: upx = event.getX(); upy = event.getY(); if(Math.abs(downx - upx) > 50 || Math.abs(downy - upy) > 50){ fling = true; }else{ fling = false; } break; } if(x< width && y < 6*width/7f && !fling){ String[] s = date.get(getXRY(x)+getXRY(y)).split(","); Calendar d = Calendar.getInstance(); d.set(year, Integer.parseInt(s[0]) - 1, Integer.parseInt(s[1])); selectCalendarListener.onSelectCalendar(d.getTime()); if(curDate.getMonth() == (Integer.parseInt(s[0])-1)){ curDate = d.getTime(); } } return gd.onTouchEvent(event); } public void setCalendarListener(SelectCalendarListener selectCalendarListener){ this.selectCalendarListener = selectCalendarListener; } public void setFlingCalendarListener(FlingCalendarListener flingCalendarListener){ this.flingCalendarListener = flingCalendarListener; } @Override public boolean onDown(MotionEvent e) { return true; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if(velocityX > 20){ flingCalendarListener.onFlingCalendar(lastMonth()); }else if(velocityX < -20){ flingCalendarListener.onFlingCalendar(nextMonth()); } return false; } public interface SelectCalendarListener{ public void onSelectCalendar(Date downdate); } public interface FlingCalendarListener{ public void onFlingCalendar(Date flingdate); } public String getXRY(float point){ String key = ""; int keyx = (int)(point/((1/2f)*width/7f)); switch(keyx){ case 0: key = "0"; break; case 1: key = "0"; break; case 2: key = "1"; break; case 3: key = "1"; break; case 4: key = "2"; break; case 5: key = "2"; break; case 6: key = "3"; break; case 7: key = "3"; break; case 8: key = "4"; break; case 9: key = "4"; break; case 10: key = "5"; break; case 11: key = "5"; break; case 12: key = "6"; break; case 13: key = "6"; break; } return key; } private void initDate(Date date){ radius = width/14f-10; circlep = new Paint(); circlep.setColor(Color.parseColor("#ffffff")); circlep.setAntiAlias(true); circlep.setTextSize(18); textp = new Paint(); textp.setColor(Color.parseColor("#e23086")); textp.setAntiAlias(true); textp.setTextSize(18); todayp = new Paint(); todayp.setColor(Color.parseColor("#e23086")); todayp.setAntiAlias(true); todayp.setStyle(Paint.Style.STROKE); curDate = date; mcalendar = Calendar.getInstance(); mcalendar.setTime(curDate); } }
實現使用
package com.example.lshan.canvascalendar; import android.app.Activity; import android.graphics.drawable.BitmapDrawable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class MainActivity extends Activity implements View.OnClickListener{ private Button popupbtn; private TextView tv_date; private View contextView; private CanvasCalendar canvasCalendar; private Date date; private Date today; private Date LastNext; private Button lastmonth,nextmonth; private TextView ymd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_popupwindow); } @Override public void onContentChanged() { super.onContentChanged(); popupbtn = (Button)findViewById(R.id.popupwindow); popupbtn.setOnClickListener(this); tv_date = (TextView)findViewById(R.id.date); contextView = LayoutInflater.from(this).inflate(R.layout.activity_main,null); lastmonth = (Button)contextView.findViewById(R.id.lastmonth); lastmonth.setOnClickListener(this); nextmonth = (Button)contextView.findViewById(R.id.nextmonth); nextmonth.setOnClickListener(this); canvasCalendar = (CanvasCalendar)contextView.findViewById(R.id.layout_calendar); ymd = (TextView)contextView.findViewById(R.id.ymd); date = new Date(); today = new Date(); ymd.setText(new SimpleDateFormat("yy-MM-dd").format(date)); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); canvasCalendar.setWidth(dm.widthPixels); } @Override public void onClick(View v) { switch(v.getId()){ case R.id.popupwindow: canvasCalendar.setDate(date); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); final PopupWindow popupWindow = new PopupWindow(contextView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT,true); popupWindow.setOutsideTouchable(true); popupWindow.setBackgroundDrawable(new BitmapDrawable()); popupWindow.setFocusable(true); popupWindow.showAsDropDown(popupbtn); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(dm.widthPixels,(int)Math.ceil(dm.widthPixels*6/7.0)); canvasCalendar.setCalendarListener(new CanvasCalendar.SelectCalendarListener() { @Override public void onSelectCalendar(Date downdate) { ymd.setText(new SimpleDateFormat("yy-MM-dd").format(downdate)); date = downdate; popupWindow.dismiss(); } }); popupWindow.setTouchInterceptor(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.i("hima","touch"); if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { popupWindow.dismiss(); } return false; } }); canvasCalendar.setFlingCalendarListener(new CanvasCalendar.FlingCalendarListener() { @Override public void onFlingCalendar(Date flingdate) { ymd.setText(new SimpleDateFormat("yy-MM-dd").format(flingdate)); date = flingdate; } }); break; case R.id.lastmonth: LastNext = canvasCalendar.lastMonth(); ymd.setText(new SimpleDateFormat("yy-MM-dd").format(LastNext)); date = LastNext; break; case R.id.nextmonth: LastNext = canvasCalendar.nextMonth(); ymd.setText(new SimpleDateFormat("yy-MM-dd").format(LastNext)); date = LastNext; break; } } }
佈局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/popupwindow"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/date"/> </LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:orientation="vertical"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="0.0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:text="lastmonth" android:id="@+id/lastmonth" /> <TextView android:layout_width="0.0dip" android:layout_height="wrap_content" android:layout_weight="2.0" android:layout_gravity="center" android:gravity="center" android:id="@+id/ymd"/> <Button android:layout_width="0.0dip" android:layout_height="wrap_content" android:layout_weight="1.0" android:text="nextmonth" android:id="@+id/nextmonth" /> </LinearLayout> <com.example.lshan.canvascalendar.CanvasCalendar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/layout_calendar" /> </LinearLayout>