সময়, দিন, মাস, বছর এবং দিনের পরিসীমা বাছাই করার জন্য কিভাবে PickerDialog ব্যবহার করা যায় তা নিয়ে আজকে আমরা কথা বলব।

অ্যান্ড্রয়েডে কাজ করতে গিয়ে প্রায়ই বিভিন্ন কাজে সময় বাছাই করা প্রয়োজন হয়। যেমন, অ্যালার্ম সেট করতে একটি নির্দিষ্ট সময় দেয়া লাগে, রিমাইন্ডার দিতে হলে একটি সময়ের সাথে দিনও বাছাই করতে হয়। আবার ফিটনেস অ্যাপগুলোতে নির্দিষ্ট সময়ের তথ্য দেখার জন্য মাস বা বছর সিলেক্ট করা প্রয়োজন হতে পারে। হোটেল বা ফ্লাইট বুকিং করার জন্য একটি নির্দিষ্ট দিনের পরিসীমা সিলেক্ট করে দিতে হয়। এছাড়াও বিভিন্ন কাজে এমন বিভিন্ন ধরণের সময় নির্বাচন করা দরকার হতে পারে। এজন্যই আমরা আজকে এদের Picker-গুলো দেখব।

PickerExamples অ্যাপ

Picker-গুলো দেখানোর জন্য একটি সোজাসাপ্টা অ্যান্ড্রয়েড অ্যাপ বানানো হয়েছে। অ্যাপ্লিকেশনের একমাত্র পেজে সবার উপরে একটি TextView রাখা হয়েছে। Picker-গুলোর মাধ্যমে আমরা যে সময়/দিন/মাস/বছর/দিনের পরিসীমা বাছাই করব তা আমরা এই TextView-তে দেখতে পাব। TextView-তে প্রাথমিকভাবে বর্তমান দিনের তথ্য দেখানো হচ্ছে। TextView-এর নিচে পাঁচটি TextButton আছে যেগুলো ক্লিক করে আমরা যথাক্রমে সময়, দিন, মাস, বছর এবং দিনের পরিসীমার PickerDialog ওপেন করব।

PickerExamples অ্যাপ্লিকেশন

বিভিন্ন তথ্যগুলো নির্দিষ্ট ফরম্যাটে দেখানোর জন্য কিছু SimpleDateFormat নেয়া হয়েছে। যেহেতু বছর মূলত একটি সংখ্যা তাই বছরের জন্য কোন ফরম্যাট প্রয়োজন হয়নি। আর দিনের পরিসীমাতে দুইটি দিন আছে বলে এটা ম্যানুয়ালি দেখানো হয়েছে।

SimpleDateFormat timeFormat, dateFormat, monthFormat;
timeFormat = new SimpleDateFormat("hh:mm a", Locale.getDefault());
dateFormat = new SimpleDateFormat("dd MMM, yyyy", Locale.getDefault());
monthFormat = new SimpleDateFormat("MMM, yyyy", Locale.getDefault());

অ্যাপ্লিকেশনের কাজের পদ্ধতি বোঝার জন্য যা যা দেখা প্রয়োজন সেসব আমরা দেখলাম। এবার আমরা Picker-গুলো একটি একটি করে দেখে নেবো।

TimePicker

TimePicker-এর মাধ্যমে আমরা দিনের একটি নির্দিষ্ট সময় বাছাই করতে পারি। timePicker বাটনটি ক্লিক করলে প্রথমে একটি Calendar অবজেক্ট তৈরি করছি এবং এর ঘণ্টা ও মিনিট সেভ করে রাখছি প্যারামিটারে পাঠানোর জন্য। এরপর একটি TimePickerDialog তৈরি করছি। এই ডায়লগে পাঁচটি প্যারামিটার লাগে। প্রথমে Context হিসেবে এই Activity-র রেফারেন্স দিচ্ছি। এরপরের প্যারামিটারে TimePicker-এর OnTimeSetListener পাঠাতে হবে যেখানে onTimeSet ফাংশনটি ওভাররাইড করে বলে দিতে হবে যে সময় বাছাই করা হলে কি করা হবে। এই ফাংশনের তিনটি প্যারামিটারের দ্বিতীয় এবং তৃতীয়টিতে বাছাইকৃত ঘণ্টা এবং মিনিট থাকবে। আমরা আমাদের calendar-এর ঘণ্টা এবং মিনিট হিসেবে এই দুটি মান সেট করব। এরপর calendar-এর পরিবর্তিত সময়কে timeFormat-এর মাধ্যমে ফরম্যাট করে TextView-তে দেখাব।

new TimePickerDialog.OnTimeSetListener() {
    @Override
    public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {
        calendar.set(Calendar.HOUR_OF_DAY, selectedHour);
        calendar.set(Calendar.MINUTE, selectedMinute);
        time = timeFormat.format(calendar.getTime());
        timeText.setText(time);
    }
}

তৃতীয় এবং চতুর্থ প্যারামিটারে হিসেবে ঘণ্টা এবং মিনিট পাঠাতে হবে যা ডায়লগ ওপেন করলে দেখানো হবে। আমরা আমাদের calendar-এর ঘণ্টা এবং মিনিটকেই এখানে পাঠাব। শেষের প্যারামিটারে একটি boolean পাঠাতে হবে, true পাঠালে ডায়লগটি ২৪ ঘণ্টা ভিউতে থাকবে এবং false পাঠালে ডায়লগটি ১২ ঘণ্টা ভিউতে AM/PM সহ থাকবে। আমরা ডায়লগটি ১২ ঘণ্টা ভিউতে দেখতে চাই তাই true পাঠিয়েছি। এবার ডায়লগের show() মেথডটি কল করলে ডায়লগটি দেখাবে। সম্পূর্ণ কোডটি নিচে দেয়া হল।

Button timePicker = findViewById(R.id.timePicker);
timePicker.setOnClickListener(new View.OnClickListener() {
    Calendar calendar = Calendar.getInstance();
    int hour = calendar.get(Calendar.HOUR);
    int minute = calendar.get(Calendar.MINUTE);

    @Override
    public void onClick(View view) {
        new TimePickerDialog(MainActivity.this, new TimePickerDialog.OnTimeSetListener() {
            @Override
            public void onTimeSet(TimePicker timePicker, int selectedHour, int selectedMinute) {
                calendar.set(Calendar.HOUR_OF_DAY, selectedHour);
                calendar.set(Calendar.MINUTE, selectedMinute);
                time = timeFormat.format(calendar.getTime());
                timeText.setText(time);
            }
        }, hour, minute, false).show();
    }
});

TimePickerDialog

show() মেথড কল করার আগে PickerDialog-এর বিভিন্ন বৈশিষ্ট্য সেট করার জন্য অন্যান্য মেথড কল করা যায়।

setTitle();
setMessage();
setIcon();

DatePicker

একটি নির্দিষ্ট দিন বাছাই করার জন্য datePicker বাটন ক্লিক করলে আমরা আগের মত আগে একটি Calendar অবজেক্ট তৈরি করে এর বছর, মাস এবং দিন সেভ করে রাখছি। এরপর আমরা একটি DatePickerDialog ওপেন করছি। এই ডায়লগেও আমরা পাঁচটি প্যারামিটারে পাঠাচ্ছি যার প্রথমটি Context এবং দ্বিতীয়টি onDateSetListener যার onDateSet ফাংশনটি আমরা ওভাররাইড করব। আগের মতই এখানেও আমরা প্যারামিটারে দেয়া বছর, মাস এবং দিনের মান আমাদের calendar-এ সেট করে dateFormat-এর মাধেমে ফরম্যাট করে TextView-তে দেখাচ্ছি। তৃতীয়, চতুর্থ এবং পঞ্চম প্যারামিটারে বছর, মাস এবং দিন পাঠাতে হবে যেখানে আমরা আমাদের calendar থেকে সেভ করা তথ্য পাঠাব। এখানে লক্ষ করি যে ডায়লগটিকে dialog ভ্যারিয়েবলের মধ্যে রাখা হয়েছে। এরপর getDatePicker()-এর মাধ্যমে সর্বোচ্চ দিন হিসেবে বর্তমান সময়কে সেট করা হয়েছে।

dialog.getDatePicker().setMaxDate(calendar.getTimeInMillis());

এভাবে getDatePicker()-এর মাধ্যমে আরও বিভিন্ন মান সেট করা যায়।

setMinDate();
setFirstDayOfTheWeek();
setBackground();
setBackgroundColor();

এভাবে সব মান সেট করার পর dialog.show() মেথড কল করে ডায়লগটি দেখাব। পুরো কোডটি একবার দেখে নেই।

Button datePicker = findViewById(R.id.datePicker);
datePicker.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        final Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);

        DatePickerDialog dialog = new DatePickerDialog(MainActivity.this, new DatePickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(DatePicker datePicker, int selectedYear, int selectedMonth, int selectedDay) {
                calendar.set(Calendar.YEAR, selectedYear);
                calendar.set(Calendar.MONTH, selectedMonth);
                calendar.set(Calendar.DAY_OF_MONTH, selectedDay);
                time = dateFormat.format(calendar.getTime());
                timeText.setText(time);
            }
        }, year, month, day);
        dialog.getDatePicker().setMaxDate(calendar.getTimeInMillis());
        dialog.show();
    }
});

Imgur

MonthPicker

এবার আসি MonthPickerDialog-এ। মাস বাছাইয়ের জন্য কোন ডিফল্ট ডায়লগ না থাকায় আমরা এর জন্য একটি ওপেনসোর্স লাইব্রেরি ব্যবহার করছি। লাইব্রেরিটি হল premkumarroyal/MonthAndYearPicker। এই লাইব্রেরিটি ব্যবহার করার জন্য প্রথমে অ্যাপ্লিকেশনের অ্যাপ লেভেলের build.gradle-এ এই লাইব্রেরির ডিপেন্ডেন্সি যোগ করতে হবে।

dependencies {
    ...
    implementation 'com.whiteelephant:monthandyearpicker:1.3.0'
}

এবার আমরা monthPicker বাটন ক্লিক করে একটি MonthPickerDialog.Builder ওপেন করব। এর onDateSetListener-এর onDateSet ফাংশনটি ওভাররাইড করে প্যারামিটারে দেয়া মাস এবং বছর calendar-এ সেট করে নিচ্ছি। এরপর monthFormat-এর মাধ্যমে TextView-তে দেখাচ্ছি। আমরা একটি Builder নিয়েছি তাই show() মেথডের আগে build() মেথড কল করতে হবে।

Button monthPicker = findViewById(R.id.monthPicker);
monthPicker.setOnClickListener(new View.OnClickListener() {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);

    @Override
    public void onClick(View view) {
        new MonthPickerDialog.Builder(MainActivity.this, new MonthPickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(int selectedMonth, int selectedYear) {
                calendar.set(Calendar.YEAR, selectedYear);
                calendar.set(Calendar.MONTH, selectedMonth);
                time = monthFormat.format(calendar.getTime());
                timeText.setText(time);
            }
        }, year, month)
                .build()
                .show();
    }
});

MonthPickerDialog

আগের ডায়লগগুলোর মত এখানেও বিভিন্ন মেথড কল করে মান সেট করা যায়, কিন্তু কল করতে হবে build() কল করার আগে।

setTitle();
setMinMonth();
setMaxMonth();
setMinYear();
setMaxYear();
setMonthRange();
setYearRange();
showMonthOnly();

YearPicker

YearPickerDialog-এর জন্য আমরা আগের লাইব্রেরিটাই ব্যবহার করব। পার্থক্য একটাই, build() কল করার আগে showYearOnly() মেথডটি কল করব যেন ডায়লগে শুধু বছর দেখায়। যেহেতু একই লাইব্রেরি ব্যবহার করা হচ্ছে, সুতরাং, আগের মেথডগুলো আমরা এখানেও ব্যবহার করতে পারব।

Button yearPicker = findViewById(R.id.yearPicker);
yearPicker.setOnClickListener(new View.OnClickListener() {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);

    @Override
    public void onClick(View view) {
        new MonthPickerDialog.Builder(MainActivity.this, new MonthPickerDialog.OnDateSetListener() {
            @Override
            public void onDateSet(int selectedMonth, int selectedYear) {
                calendar.set(Calendar.YEAR, selectedYear);
                time = String.valueOf(calendar.get(Calendar.YEAR));
                timeText.setText(time);
            }
        }, year, month)
                .showYearOnly()
                .build()
                .show();
    }
});

YearPickerDialog

DateRangePicker

এবার আমরা DateRangePickerDialog নিয়ে কাজ করব যার মাধ্যমে আমরা একটি নির্দিষ্ট দিন থেকে শুরু করে আরেকটি দিন পর্যন্ত পরিসীমা বাছাই করতে পারি। কোন ডিফল্ট না থাকায় এর জন্য আমরা আরেকটি লাইব্রেরি ব্যবহার করব। আমরা যে ওপেনসোর্স লাইব্রেরিটি এখানে ব্যবহার করছি সেটি হল ArchitShah248/CalendarDateRangePicker। আগের মত এই লাইব্রেরির ডিপেন্ডেন্সি আমরা যোগ করে নেই।

dependencies {
    ...
    implementation 'com.archit.calendar:awesome-calendar:1.1.4'
}

অন্যান্য Picker-গুলোর মত এটি একটি ডায়লগ নয়, বরং একটি ভিউ। তাই একে ডায়লগ হিসেবে ব্যবহার করার জন্য আমরা আগে একটি লে-আউটে একে বসিয়ে নেব। এরপর ডিফল্ট AlertDialog.Builder-এর ভিউ হিসেবে ওই লে-আউটটিকে সেট করে দিব। তাহলে শুরু করা যাক।

প্রথমে একটি সাধারণ লে-আউট বানাই, যার নাম আমরা দিচ্ছি layout_date_range_picker.xml। এখানে LinearLayout এর মধ্যে DateRangeCalendarView বসাই। লে-আউটের কাজ এতটুকুই।

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <com.archit.calendardaterangepicker.customviews.DateRangeCalendarView
        android:id="@+id/date_picker_dialog"
        custom:enable_past_date="true"
        custom:range_color="@color/colorPrimaryLight"
        custom:selected_date_circle_color="@color/colorPrimaryDark"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

rangePicker বাটন ক্লিক করে আমরা এই Picker-টি ডায়লগে ওপেন করতে চাই। এজন্য আমরা প্রথমে আমাদের লে-আউটটি inflate করে pickerLayout-এ সেভ করি। লে-আউটের প্রথম এবং একমাত্র child হল DateRangeCalendarView যাকে আমরা datePicker-এ রাখছি। এবার এর setCalendarListener-এর দুটি মেথড ওভাররাইট করতে হবে। আমরা onFirstDateSelected মেথড কল হয় যখন প্রথম দিন বাছাই করা হয়, এখানে আমরা প্রথম দিনের ফরম্যাট সেভ করে রাখছি। onDateRangeSelected মেথড কল হয় যখন প্রথম এবং শেষ দিন দুটিই বাছাই করা হয়। এখানে আমরা প্রথম দিন এবং শেষ দিনের ফরম্যাট যুক্ত করে সেভ করে রাখছি।

এরপর আমরা একটি AlertDialog.Builder নিয়ে একটি মেসেজ সেট করে দিয়েছি। এর ভিউ হিসেবে আমাদের pickerLayout কে সেট করি। এর setCancelable()-কে true করে দিয়েছি অর্থাৎ ডায়লগের বাইরে ক্লিক করলে ডায়লগটি ডিসমিস হয়ে যাবে। এবার setPositiveButton()-এ আমরা সেভ করা পরিসীমার ফরম্যাট দেখাচ্ছি। setNegativeButton()-টি ও কল করছি যেন Cancel বাটনে ক্লিক করলে ডায়লগটি ডিসমিস হয়ে যায়। সবশেষে ডায়লগটি দেখাচ্ছি।

Button rangePicker = findViewById(R.id.rangePicker);
rangePicker.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        LinearLayout pickerLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.layout_date_range_picker, null, false);
        DateRangeCalendarView datePicker = (DateRangeCalendarView) pickerLayout.getChildAt(0);
        datePicker.setCalendarListener(new DateRangeCalendarView.CalendarListener() {
            @Override
            public void onFirstDateSelected(Calendar start) {
                time = dateFormat.format(start.getTime());
            }

            @Override
            public void onDateRangeSelected(Calendar start, Calendar end) {
                time = dateFormat.format(start.getTime()).concat(" - ").concat(dateFormat.format(end.getTime()));
            }
        });

        new AlertDialog.Builder(MainActivity.this)
                .setMessage("শুরুর দিন এবং শেষ দিনে ক্লিক করে দিনের পরিসীমা সিলেক্ট করুন")
                .setView(pickerLayout)
                .setCancelable(true)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                        timeText.setText(time);
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                    }
                })
                .show();
    }
});

DateRangePickerDialog


যে অ্যাপ্লিকেশনটি বানিয়ে আমরা এই কাজগুলো করলাম তার পুরো কোড ams-hasan/PickerExamples-এই রিপোসিটোরিতে আছে। আশা করি এরপর প্রয়োজনে সহজেই দরকারি ডায়লগটি ব্যবহার করতে পারব।