TheDevMan
TheDevMan

Reputation: 5954

CalendarView in Android

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!

Upvotes: 0

Views: 3655

Answers (1)

tianyu
tianyu

Reputation: 179

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.

Upvotes: 1

Related Questions