0

I have implemented CalendarView in my project and I would like to get the DD/MM/YY format on clicking the date

I tried the following:

calendar =(CalendarView) findViewById(R.id.calendarforstart);
calendar.setShowWeekNumber(false);
    calendar.setFirstDayOfWeek(2);
    calendar.setOnDateChangeListener(new OnDateChangeListener() 
    {
        @Override
        public void onSelectedDayChange(CalendarView view, int year, int month, int day) 
        {
            Toast.makeText(getApplicationContext(), day + "/" + month + "/" + year, Toast.LENGTH_LONG).show();
        }
    });

The above works fine but if I scroll the calendar to next month or previous month. I am getting the Toast, which I don't want instead, I would like to get the toast only when I click on the on a date?

How do I implement this?

Let me know!

Thanks!

TheDevMan
  • 5,914
  • 12
  • 74
  • 144
  • Can you use a long variable live `private long lastDate = 0;` to store the date status? – tianyu Mar 27 '15 at 03:44
  • This [Android: CalendarView OnDateChangeLIstener](http://stackoverflow.com/questions/12641250/android-calendarview-ondatechangelistener) may help you a lot. – tianyu Mar 27 '15 at 03:56
  • @tianyu : By doing this I cannot select the current date. :( How to do that? – TheDevMan Mar 27 '15 at 07:22
  • Try override `dispatchTouchEvent(MotionEvent event)`, in `MotionEvent.ACTION_UP` save the touch x,y point and check if is near lastDate's point. I will add some sample code later. – tianyu Mar 27 '15 at 10:12

1 Answers1

1

To solve cannot select the current date is a hard way. The idea is save each list item's screen position, and check every dispatchTouchEvent if (x,y) is inside a date view item.

private long lastDate = 0;

private int downX;
private int downY;

private int upX;
private int upY;

private int lastX=0;
private int lastY=0;

private ItemArea currentArea;

private int year = -1;
private int month;
private int day;

private ListView listView;

private int[] startPoint = new int[2];

private int listItemCount = 0;
private int listItemWidth = 0;
private int listItemHeight = 0;

ArrayList<ItemArea> areaList = new ArrayList<>();

private CalendarView calendar;

private boolean isInitialized = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    calendar =(CalendarView) findViewById(R.id.calendarforstart);
    calendar.setShowWeekNumber(false);
    calendar.setFirstDayOfWeek(2);
    calendar.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
        @Override
        public void onSelectedDayChange(CalendarView view, int year, int month, int day) {
            if(view.getDate() != lastDate) {
                lastDate = view.getDate();
                MainActivity.this.year = year;
                MainActivity.this.month = month;
                MainActivity.this.day = day;
                makeToast();
                currentArea = getItemArea(upX, upY);
                isInitialized = true;
            }
        }
    });

    listView = (ListView)calendar.findViewById(android.R.id.list);

}

@Override
public boolean dispatchTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downX = (int)event.getX();
            downY = (int)event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_UP:
            upX = (int)event.getX();
            upY = (int)event.getY();

            if (areaList.size()==0) {
                generateList();
            }

            // make sure it's not move
            if (Math.abs(downX-upX)<3 && Math.abs(downY-upY)<3) {
                ItemArea area = getItemArea(upX, upY);

                // on application start up and click the current date, there are stored status.
                if (currentArea==null || !isInitialized) {
                    long time = calendar.getDate();
                    Calendar currentCalendar = new GregorianCalendar();
                    currentCalendar.setTimeInMillis(time);
                    year = currentCalendar.get(Calendar.YEAR);
                    month = currentCalendar.get(Calendar.MONTH);
                    day = currentCalendar.get(Calendar.DAY_OF_MONTH);
                    makeToast();
                }

                if (area!=null && area.equals(currentArea)) {
                    makeToast();
                }
            } else {
                // FIXME: still have bug when drag/scroll back
                // it's move event, list view will scroll up/down, and update the y
                if (currentArea!=null) {
                    if (downY<upY) {
                        // move down
                        int times = (upY-downY)/listItemHeight;
                        currentArea.top+=listItemHeight*(times+1);
                        currentArea.bottom+=listItemHeight*(times+1);
                    } else {
                        // move up
                        int times = (downY-upY)/listItemHeight;
                        currentArea.top-=listItemHeight*(times+1);
                        currentArea.bottom-=listItemHeight*(times+1);
                    }
                }
            }
            break;
    }

    return super.dispatchTouchEvent(event);
}

private void generateList() {
    listItemCount = listView.getChildCount();
    listItemHeight = listView.getChildAt(0).getHeight();
    listItemWidth = listView.getChildAt(0).getWidth();
    listView.getChildAt(0).getLocationOnScreen(startPoint);

    int deltaX = (int)(listItemWidth/7.0);

    for (int i=0; i< listItemCount; i++) {
        for (int j=0; j<7; j++) {
            areaList.add(new ItemArea(startPoint[0]+deltaX*j, startPoint[1]+listItemHeight*i,
                    startPoint[0]+deltaX*(j+1), startPoint[1]+listItemHeight*(i+1)));
        }

    }

}

private void makeToast() {
    Log.d("TAG", "do your job here");
    lastX = upX;
    lastY = upY;

    Toast.makeText(this, "" + day + "/" + month + "/" + year, Toast.LENGTH_LONG).show();
}

private ItemArea getItemArea(int x, int y) {
    for (int i=0; i < areaList.size(); i++) {
        if (areaList.get(i).contains(x, y)) {
            return areaList.get(i);
        }
    }
    return null;
}

private class ItemArea {
    int left;
    int top;
    int right;
    int bottom;

    ItemArea(int left, int top, int right, int bottom) {
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
    }

    boolean contains(int x, int y) {
        return x>=left && x<=right && y>=top && y<=bottom;
    }

    boolean equals(ItemArea area) {
        return area!=null &&
                this.right==area.right &&
                this.left==area.left &&
                this.bottom==area.bottom &&
                this.top==area.top;
    }
}

UPDATE

In API 22 (android 5.1), android has changed CalendarView to MATERIAL . There is no ListView at all, check the code from CalendarView MODE_MATERIAL and calendarViewMode

So the above code fails if you use default style, the only way is force using CalendarViewLegacyDelegate which means set calendarViewMode to MODE_HOLO. You can do this by adding style="@android:style/Widget.CalendarView" which is simply like this:

<CalendarView
    android:id="@+id/calendarforstart"
    style="@android:style/Widget.CalendarView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

But you will lost your material UI. You can extends Widget.CalendarView for your needs, but I think it's still far away from material.

tianyu
  • 179
  • 2
  • 6
  • Hey! Thanks for the quick reply. Sorry for the delay was travelling and could try this and also reply you. I am trying this now and keep you posted? A quick question why do you require listView here? – TheDevMan Apr 01 '15 at 13:06
  • Also the month is in April 2015 but when I get a toast it is showing march? Any idea with that? – TheDevMan Apr 01 '15 at 13:10
  • Wow...@tianyu... You saved my day! Thanks a lot! This is working.. Can you please explain what exactly you have done? – TheDevMan Apr 01 '15 at 23:47
  • `CalendarView` is actually `ListView` inside, so if we get our touch point on screen from `dispatchTouchEvent` and caculate every ListItem of date's position then we can know exactly which date we are click. If we touch a different date, `onSelectedDayChange` is called and it's easy for your need. But if we touch the same date, `onSelectedDayChange` is not called so we have to detect it's a click or touching or scrolling. – tianyu Apr 02 '15 at 01:43
  • `Why showing march` is because `The month value is 0-based`, get `Calendar.MONTH` returns `0-11`. This may be a common sense in coding, I thought you have already know it, see more from here [Why is January month 0 in Java Calendar?](http://stackoverflow.com/questions/344380/why-is-january-month-0-in-java-calendar) – tianyu Apr 02 '15 at 01:51
  • Got it! Thanks a lot! I have learnt something new on calendar part. :) – TheDevMan Apr 02 '15 at 01:52
  • BTW: is it possible to add events in the calendarView? I mean I just need to add one TextView for a given date? – TheDevMan Apr 02 '15 at 01:53
  • @TheDevMan Sorry I have no idea to add events in `CalendarView`, maybe you should post a new question for this to ask someone else.Or you can use a third part `CalendarView` [Add event to CalendarView](http://stackoverflow.com/questions/22000585/add-event-to-calendarview) or just create your own custom CalendarView for this. – tianyu Apr 02 '15 at 02:00
  • No worries. I am happy atleast I am able to click on the currentDate. Thanks a lot tianyu! – TheDevMan Apr 02 '15 at 02:04
  • Hey! You solved my day... now I have an issue. I changed my Theme to AppCompat.Light.Actionbar after that I have an issue in generateList() throws NP Expections for Lollipop versions. I have the log here: http://pastebin.com/860kZPic - I have been trying find out what could be wrong not able to fix it. Can you help me out with this? Thanks! – TheDevMan Jun 02 '15 at 07:10