การปรับแต่ง Android: วิธีสร้างส่วนประกอบ UI ที่ทำในสิ่งที่คุณต้องการ

เผยแพร่แล้ว: 2022-03-11

ไม่ใช่เรื่องแปลกที่นักพัฒนาซอฟต์แวร์จะพบว่าตัวเองต้องการส่วนประกอบ UI ที่ไม่ได้มาจากแพลตฟอร์มที่พวกเขากำลังกำหนดเป้าหมายหรือจัดหาให้ แต่ไม่มีคุณสมบัติหรือพฤติกรรมบางอย่าง คำตอบสำหรับทั้งสองสถานการณ์คือองค์ประกอบ UI ที่กำหนดเอง

โมเดล UI ของ Android นั้นปรับแต่งได้เองตามธรรมชาติ โดยนำเสนอวิธีการปรับแต่ง การทดสอบ และความสามารถในการสร้างส่วนประกอบ UI ที่กำหนดเองของ Android ด้วยวิธีต่างๆ:

  • สืบทอดองค์ประกอบที่มีอยู่ (เช่น TextView , ImageView ฯลฯ ) และเพิ่ม/แทนที่ฟังก์ชันที่จำเป็น ตัวอย่างเช่น CircleImageView ที่สืบทอด ImageView แทนที่ onDraw() เพื่อจำกัดรูปภาพที่แสดงเป็นวงกลม และเพิ่ม loadFromFile() เพื่อโหลดรูปภาพจากหน่วยความจำภายนอก

  • สร้างองค์ประกอบแบบผสม จากหลายองค์ประกอบ วิธีนี้มักจะใช้ประโยชน์จาก Layouts เพื่อควบคุมวิธีการจัดเรียงส่วนประกอบบนหน้าจอ ตัวอย่างเช่น LabeledEditText ที่สืบทอด LinearLayout โดยมีการวางแนวนอน และมีทั้ง TextView ที่ทำหน้าที่เป็นป้ายกำกับและ EditText ที่ทำหน้าที่เป็นช่องป้อนข้อความ

    วิธีการนี้ยังสามารถใช้ประโยชน์จากวิธีก่อนหน้านี้ เช่น ส่วนประกอบภายในอาจเป็นแบบเนทีฟหรือแบบกำหนดเองก็ได้

  • แนวทางที่หลากหลายและซับซ้อนที่สุดคือการ สร้างองค์ประกอบที่วาดเอง ในกรณีนี้ ส่วนประกอบจะสืบทอดคลาส View ทั่วไปและแทนที่ฟังก์ชันเช่น onMeasure() เพื่อกำหนดเลย์เอาต์, onDraw() เพื่อแสดงเนื้อหา ฯลฯ ส่วนประกอบที่สร้างด้วยวิธีนี้มักจะขึ้นอยู่กับ API การวาด 2D ของ Android เป็นอย่างมาก

กรณีศึกษาการปรับแต่ง Android: The CalendarView

Android มีคอมโพเนนต์ CalendarView ดั้งเดิม ทำงานได้ดีและมีฟังก์ชันการทำงานขั้นต่ำที่คาดไว้จากองค์ประกอบปฏิทินใดๆ โดยแสดงทั้งเดือนและเน้นวันที่ปัจจุบัน บางคนอาจบอกว่าดูดีเช่นกัน แต่ถ้าคุณกำลังมองหารูปลักษณ์ดั้งเดิมและไม่สนใจในการปรับแต่งรูปลักษณ์ใด ๆ

ตัวอย่างเช่น คอมโพเนนต์ CalendarView ไม่มีทางเปลี่ยนแปลงวิธีการทำเครื่องหมายวันใดวันหนึ่ง หรือสีพื้นหลังใดที่จะใช้ นอกจากนี้ยังไม่มีวิธีเพิ่มข้อความหรือกราฟิกที่กำหนดเองเพื่อทำเครื่องหมายโอกาสพิเศษ เป็นต้น กล่าวโดยสรุป ส่วนประกอบมีลักษณะดังนี้ และแทบไม่มีอะไรเปลี่ยนแปลงได้:

ภาพหน้าจอ
CalendarView ในธีม AppCompact.Light

ทำด้วยตัวคุณเอง

แล้วเราจะสร้างมุมมองปฏิทินของตัวเองได้อย่างไร? วิธีการใด ๆ ข้างต้นจะได้ผล อย่างไรก็ตาม การใช้งานจริงมักจะตัดตัวเลือกที่สาม (กราฟิก 2 มิติ) ออก และปล่อยให้เราใช้วิธีอื่นอีกสองวิธี และเราจะใช้ทั้งสองอย่างผสมกันในบทความนี้

หากต้องการติดตาม คุณสามารถค้นหาซอร์สโค้ดได้ที่นี่

1. เค้าโครงส่วนประกอบ

อันดับแรก มาเริ่มกันที่ส่วนประกอบที่มีลักษณะ เพื่อให้ง่ายขึ้น ให้แสดงวันในตาราง และที่ด้านบนสุด ชื่อของเดือนพร้อมกับปุ่ม "เดือนหน้า" และ "เดือนก่อน"

ภาพหน้าจอ
มุมมองปฏิทินที่กำหนดเอง

โครงร่างนี้ถูกกำหนดในไฟล์ control_calendar.xml ดังนี้ โปรดทราบว่ามาร์กอัปซ้ำ ๆ บางตัวย่อด้วย ... :

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andro android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white"> <!-- date toolbar --> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="12dp" android:paddingBottom="12dp" android:paddingLeft="30dp" android:paddingRight="30dp"> <!-- prev button --> <ImageView android: android:layout_width="30dp" android:layout_height="30dp" android:layout_centerVertical="true" android:layout_alignParentLeft="true" android:src="@drawable/previous_icon"/> <!-- date title --> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toRightOf="@+id/calendar_prev_button" android:layout_toLeftOf="@+id/calendar_next_button" android:gravity="center" android:textAppearance="@android:style/TextAppearance.Medium" android:textColor="#222222" android:text="current date"/> <!-- next button --> <ImageView android: ... Same layout as prev button. android:src="@drawable/next_icon"/> </RelativeLayout> <!-- days header --> <LinearLayout android: android:layout_width="match_parent" android:layout_height="40dp" android:gravity="center_vertical" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center_horizontal" android:textColor="#222222" android:text="SUN"/> ... Repeat for MON - SAT. </LinearLayout> <!-- days view --> <GridView android: android:layout_width="match_parent" android:layout_height="340dp" android:numColumns="7"/> </LinearLayout>

2. คลาสส่วนประกอบ

เค้าโครงก่อนหน้าสามารถรวมตามที่เป็นอยู่ใน Activity หรือ Fragment ได้ และจะทำงานได้ดี แต่การห่อหุ้มเป็นองค์ประกอบ UI แบบสแตนด์อโลนจะป้องกันการซ้ำซ้อนของรหัสและอนุญาตให้มีการออกแบบโมดูลาร์ โดยที่แต่ละโมดูลจะจัดการกับความรับผิดชอบเดียว

องค์ประกอบ UI ของเราจะเป็น LinearLayout เพื่อให้ตรงกับรูทของไฟล์เลย์เอาต์ XML โปรดทราบว่ารหัสจะแสดงเฉพาะส่วนที่สำคัญเท่านั้น การใช้งานองค์ประกอบอยู่ใน CalendarView.java :

 public class CalendarView extends LinearLayout { // internal components private LinearLayout header; private ImageView btnPrev; private ImageView btnNext; private TextView txtDate; private GridView grid; public CalendarView(Context context) { super(context); initControl(context); } /** * Load component XML layout */ private void initControl(Context context) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.control_calendar, this); // layout is inflated, assign local variables to components header = (LinearLayout)findViewById(R.id.calendar_header); btnPrev = (ImageView)findViewById(R.id.calendar_prev_button); btnNext = (ImageView)findViewById(R.id.calendar_next_button); txtDate = (TextView)findViewById(R.id.calendar_date_display); grid = (GridView)findViewById(R.id.calendar_grid); } }

รหัสค่อนข้างตรงไปตรงมา เมื่อสร้างแล้ว คอมโพเนนต์จะขยายเลย์เอาต์ XML และเมื่อเสร็จแล้ว คอมโพเนนต์จะกำหนดการควบคุมภายในให้กับตัวแปรในเครื่องเพื่อให้เข้าถึงได้ง่ายขึ้นในภายหลัง

3. จำเป็นต้องใช้ตรรกะบางอย่าง

ในการทำให้องค์ประกอบนี้ทำงานเป็นมุมมองปฏิทินได้จริง ตรรกะทางธุรกิจบางอย่างอยู่ในลำดับ มันอาจจะดูซับซ้อนในตอนแรก แต่จริงๆ แล้วไม่มีอะไรมากไปกว่านี้ มาทำลายมันกันเถอะ:

  1. มุมมองปฏิทินกว้างเจ็ดวัน และรับประกันได้ว่าทุกเดือนจะเริ่มต้นที่ใดที่หนึ่งในแถวแรก

  2. อันดับแรก เราต้องหาตำแหน่งที่เริ่มต้นเดือน จากนั้นกรอกตำแหน่งทั้งหมดก่อนหน้านั้นด้วยตัวเลขจากเดือนก่อนหน้า (30, 29, 28.. เป็นต้น) จนกว่าจะถึงตำแหน่ง 0

  3. จากนั้น เรากรอกวันของเดือนปัจจุบัน (1, 2, 3… ฯลฯ)

  4. หลังจากนั้นจะเป็นวันของเดือนถัดไป (เช่น 1, 2, 3. เป็นต้น) แต่คราวนี้เราจะเติมเฉพาะตำแหน่งที่เหลืออยู่ในแถวสุดท้ายของตารางเท่านั้น

ไดอะแกรมต่อไปนี้แสดงขั้นตอนเหล่านั้น:

ภาพหน้าจอ
ตรรกะทางธุรกิจมุมมองปฏิทินที่กำหนดเอง

ความกว้างของตารางถูกกำหนดให้เป็นเจ็ดเซลล์แล้ว ซึ่งหมายถึงปฏิทินรายสัปดาห์ แต่ความสูงล่ะ? ขนาดที่ใหญ่ที่สุดสำหรับกริดสามารถกำหนดได้โดยสถานการณ์กรณีที่เลวร้ายที่สุดของเดือนที่มี 31 วันซึ่งเริ่มในวันเสาร์ ซึ่งเป็นเซลล์สุดท้ายในแถวแรก และจะต้องเพิ่มอีก 5 แถวจึงจะแสดงทั้งหมดได้ ดังนั้นการตั้งค่าปฏิทินให้แสดงหกแถว (รวม 42 วัน) ก็เพียงพอแล้วที่จะจัดการทุกกรณี

แต่ไม่ใช่ทุกเดือนจะมี 31 วัน! เราสามารถหลีกเลี่ยงความยุ่งยากที่เกิดขึ้นได้โดยใช้ฟังก์ชันวันที่ในตัวของ Android โดยไม่จำเป็นต้องคำนวณจำนวนวันด้วยตนเอง

ดังที่ได้กล่าวไว้ก่อนหน้านี้ ฟังก์ชันวันที่ของคลาส Calendar ทำให้การใช้งานค่อนข้างตรงไปตรงมา ในองค์ประกอบของเรา updateCalendar() จะใช้ตรรกะนี้:

 private void updateCalendar() { ArrayList<Date> cells = new ArrayList<>(); Calendar calendar = (Calendar)currentDate.clone(); // determine the cell for current month's beginning calendar.set(Calendar.DAY_OF_MONTH, 1); int monthBeginningCell = calendar.get(Calendar.DAY_OF_WEEK) - 1; // move calendar backwards to the beginning of the week calendar.add(Calendar.DAY_OF_MONTH, -monthBeginningCell); // fill cells (42 days calendar as per our business logic) while (cells.size() < DAYS_COUNT) { cells.add(calendar.getTime()); calendar.add(Calendar.DAY_OF_MONTH, 1); } // update grid ((CalendarAdapter)grid.getAdapter()).updateData(cells); // update title SimpleDateFormat sdf = new SimpleDateFormat("MMM yyyy"); txtDate.setText(sdf.format(currentDate.getTime())); }

4. ปรับแต่งได้ที่ Heart

เนื่องจากส่วนประกอบที่รับผิดชอบในการแสดงวันแต่ละวันคือ GridView ที่ที่ดีในการปรับแต่งวิธีการแสดงวันคือ Adapter เนื่องจากมีหน้าที่รับผิดชอบในการเก็บข้อมูลและขยายมุมมองสำหรับแต่ละเซลล์กริด

สำหรับตัวอย่างนี้ เราต้องการสิ่งต่อไปนี้จาก CalendearView :

  • วันปัจจุบันควรเป็น ตัวหนาสีน้ำเงิน
  • วันที่นอกเดือนปัจจุบันควรเป็น สีเทา
  • วันที่จัดงานควรแสดงไอคอนพิเศษ
  • ส่วนหัวของปฏิทินควรเปลี่ยนสีขึ้นอยู่กับฤดูกาล (ฤดูร้อน ฤดูใบไม้ร่วง ฤดูหนาว ฤดูใบไม้ผลิ)

ข้อกำหนดสามข้อแรกทำได้ง่ายโดยการเปลี่ยนแอตทริบิวต์ข้อความและทรัพยากรพื้นหลัง ให้เราใช้ CalendarAdapter เพื่อทำงานนี้ ง่ายพอที่จะเป็นคลาสสมาชิกใน CalendarView โดยการแทนที่ฟังก์ชัน getView() เราสามารถบรรลุข้อกำหนดข้างต้นได้:

 @Override public View getView(int position, View view, ViewGroup parent) { // day in question Date date = getItem(position); // today Date today = new Date(); // inflate item if it does not exist yet if (view == null) view = inflater.inflate(R.layout.control_calendar_day, parent, false); // if this day has an event, specify event image view.setBackgroundResource(eventDays.contains(date)) ? R.drawable.reminder : 0); // clear styling view.setTypeface(null, Typeface.NORMAL); view.setTextColor(Color.BLACK); if (date.getMonth() != today.getMonth() || date.getYear() != today.getYear()) { // if this day is outside current month, grey it out view.setTextColor(getResources().getColor(R.color.greyed_out)); } else if (date.getDate() == today.getDate()) { // if it is today, set it to blue/bold view.setTypeface(null, Typeface.BOLD); view.setTextColor(getResources().getColor(R.color.today)); } // set text view.setText(String.valueOf(date.getDate())); return view; }

ข้อกำหนดการออกแบบขั้นสุดท้ายต้องใช้เวลาอีกเล็กน้อย ขั้นแรก ให้เพิ่มสีสำหรับสี่ฤดูกาลใน /res/values/colors.xml :

 <color name="summer">#44eebd82</color> <color name="fall">#44d8d27e</color> <color name="winter">#44a1c1da</color> <color name="spring">#448da64b</color>

จากนั้น ลองใช้อาร์เรย์เพื่อกำหนดฤดูกาลในแต่ละเดือน (สมมติว่าซีกโลกเหนือ เพื่อความง่าย ขอโทษออสเตรเลีย!) ใน CalendarView เราเพิ่มตัวแปรสมาชิกต่อไปนี้:

 // seasons' rainbow int[] rainbow = new int[] { R.color.summer, R.color.fall, R.color.winter, R.color.spring }; int[] monthSeason = new int[] {2, 2, 3, 3, 3, 0, 0, 0, 1, 1, 1, 2};

ด้วยวิธีนี้ การเลือกสีที่เหมาะสมทำได้โดยการเลือกฤดูกาลที่เหมาะสม ( monthSeason[currentMonth] ) แล้วเลือกสีที่สอดคล้องกัน ( rainbow[monthSeason[currentMonth] ) ซึ่งจะถูกเพิ่มใน updateCalendar() เพื่อให้แน่ใจว่าได้เลือกสีที่เหมาะสม ทุกครั้งที่มีการเปลี่ยนแปลงปฏิทิน

 // set header color according to current season int month = currentDate.get(Calendar.MONTH); int season = monthSeason[month]; int color = rainbow[season]; header.setBackgroundColor(getResources().getColor(color));

ด้วยเหตุนี้เราจึงได้ผลลัพธ์ดังต่อไปนี้:

การปรับแต่ง Android
สีของส่วนหัวเปลี่ยนไปตามฤดูกาล

หมายเหตุสำคัญ เนื่องจากวิธีที่ HashSet เปรียบเทียบออบเจ็กต์ การตรวจสอบ eventDays.contains(date) ด้านบนใน updateCalendar() จะไม่ให้ผลเป็นจริงสำหรับออบเจ็กต์วันที่เว้นแต่จะเหมือนกันทุกประการ จะไม่ทำการตรวจสอบพิเศษสำหรับชนิดข้อมูล Date ที่ เพื่อแก้ไขปัญหานี้ การตรวจสอบนี้จะถูกแทนที่ด้วยรหัสต่อไปนี้:

 for (Date eventDate : eventDays) { if (eventDate.getDate() == date.getDate() && eventDate.getMonth() == date.getMonth() && eventDate.getYear() == date.getYear()) { // mark this day for event view.setBackgroundResource(R.drawable.reminder); break; } }

5. มันดูน่าเกลียดในเวลาออกแบบ

ตัวเลือกของ Android สำหรับตัวยึดตำแหน่งในช่วงการออกแบบอาจเป็นเรื่องที่น่าสงสัย โชคดีที่ Android สร้างอินสแตนซ์คอมโพเนนต์ของเราเพื่อแสดงผลในตัวออกแบบ UI และเราสามารถใช้ประโยชน์จากสิ่งนี้ได้โดยการเรียก updateCalendar() ในตัวสร้างส่วนประกอบ วิธีนี้จะทำให้ส่วนประกอบใช้งานได้จริงในเวลาออกแบบ

ภาพหน้าจอ

หากการเริ่มต้นคอมโพเนนต์เรียกร้องให้มีการประมวลผลจำนวนมากหรือโหลดข้อมูลจำนวนมาก อาจส่งผลต่อประสิทธิภาพของ IDE ในกรณีนี้ Android มีฟังก์ชันที่ดีที่เรียกว่า isInEditMode() ที่สามารถใช้เพื่อจำกัดปริมาณข้อมูลที่ใช้เมื่อส่วนประกอบถูกสร้างอินสแตนซ์จริงในตัวออกแบบ UI ตัวอย่างเช่น หากมีเหตุการณ์จำนวนมากที่ต้องโหลดลงใน CalendarView เราสามารถใช้ isInEditMode() ภายใน updateCalendar() เพื่อจัดเตรียมรายการเหตุการณ์ที่ว่างเปล่า/จำกัดในโหมดการออกแบบ และโหลดเหตุการณ์จริงอย่างอื่น

6. การเรียกส่วนประกอบ

ส่วนประกอบสามารถรวมอยู่ในไฟล์โครงร่าง XML (ตัวอย่างการใช้งานสามารถพบได้ใน activity_main.xml ):

 <samples.aalamir.customcalendar.CalendarView android: android:layout_width="match_parent" android:layout_height="wrap_content"/>

และดึงออกมาเพื่อโต้ตอบเมื่อโหลดเลย์เอาต์แล้ว:

 HashSet<Date> events = new HashSet<>(); events.add(new Date()); CalendarView cv = ((CalendarView)findViewById(R.id.calendar_view)); cv.updateCalendar(events);

โค้ดด้านบนสร้าง HashSet ของเหตุการณ์ เพิ่มวันปัจจุบัน จากนั้นส่งไปที่ CalendarView ด้วยเหตุนี้ CalendarView จะแสดงวันที่ปัจจุบันเป็นสีน้ำเงินหนาและใส่เครื่องหมายเหตุการณ์ลงไปด้วย:

ภาพหน้าจอ
CalendarView แสดงกิจกรรม

7. การเพิ่มคุณสมบัติ

สิ่งอำนวยความสะดวกอื่นที่ Android มีให้คือการกำหนดแอตทริบิวต์ให้กับส่วนประกอบที่กำหนดเอง ซึ่งช่วยให้นักพัฒนา Android ใช้คอมโพเนนต์เพื่อเลือกการตั้งค่าผ่าน XML เลย์เอาต์และเห็นผลทันทีในตัวออกแบบ UI แทนที่จะต้องรอและดูว่า CalendarView จะมีลักษณะอย่างไรในขณะใช้งานจริง มาเพิ่มความสามารถในการเปลี่ยนรูปแบบวันที่ที่แสดงในส่วนประกอบ เช่น สะกดชื่อเต็มของเดือนแทนตัวย่อสามตัวอักษร

เมื่อต้องการทำเช่นนี้ จำเป็นต้องมีขั้นตอนต่อไปนี้:

  • ประกาศแอตทริบิวต์ เรียกมันว่า dateFormat และกำหนดประเภทข้อมูล string เพิ่มไปที่ /res/values/attrs.xml :
 <resources> <declare-styleable name="CalendarDateElement"> <attr name="dateFormat" format="string"/> </declare-styleable> </resources>
  • ใช้แอตทริบิวต์ในเลย์เอาต์ที่ใช้ส่วนประกอบ และกำหนดเป็นค่า "MMMM yyyy" :
 <samples.aalamir.customcalendar.CalendarView xmlns:calendarNS="http://schemas.android.com/apk/res/samples.aalamir.customcalendar" android: android:layout_width="match_parent" android:layout_height="wrap_content" calendarNS:dateFormat="MMMM yyyy"/>
  • สุดท้าย ให้ส่วนประกอบใช้ประโยชน์จากค่าแอตทริบิวต์:
 TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CalendarView); dateFormat = ta.getString(R.styleable.CalendarView_dateFormat);

] สร้างโครงการและคุณจะสังเกตเห็นการเปลี่ยนแปลงวันที่ที่แสดงในตัวออกแบบ UI เพื่อใช้ชื่อเต็มของเดือน เช่น "กรกฎาคม 2015" ลองระบุค่าต่างๆ และดูว่าเกิดอะไรขึ้น

ภาพหน้าจอ
การเปลี่ยนแอตทริบิวต์ของ CalendarView

8. การโต้ตอบกับส่วนประกอบ

ลองกดเลือกวันดูหรือยังครับ? องค์ประกอบ UI ภายในในคอมโพเนนต์ของเรายังคงทำงานในลักษณะที่คาดไว้ตามปกติ และจะเริ่มทำงานเพื่อตอบสนองต่อการกระทำของผู้ใช้ แล้วเราจะจัดการกับเหตุการณ์เหล่านั้นอย่างไร?

คำตอบประกอบด้วยสองส่วน:

  • บันทึกเหตุการณ์ภายในคอมโพเนนต์ และ
  • รายงานเหตุการณ์ไปยังพาเรนต์ขององค์ประกอบ (อาจเป็น Fragment , Activity หรือแม้แต่องค์ประกอบอื่น)

ส่วนแรกค่อนข้างตรงไปตรงมา ตัวอย่างเช่น ในการจัดการรายการกริดที่กดค้าง เรากำหนด Listener ที่เกี่ยวข้องในคลาสองค์ประกอบของเรา:

 // long-pressing a day grid.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> view, View cell, int position, long id) { // handle long-press if (eventHandler == null) return false; Date date = view.getItemAtPosition(position); eventHandler.onDayLongPress(date); return true; } });

มีหลายวิธีในการรายงานเหตุการณ์ วิธีที่ง่ายและตรงไปตรงมาคือการคัดลอกวิธีที่ Android ทำ: มันมีอินเทอร์เฟซสำหรับเหตุการณ์ของส่วนประกอบที่นำไปใช้โดยผู้ปกครองของส่วนประกอบ ( eventHandler ในข้อมูลโค้ดด้านบน)

ฟังก์ชันของอินเทอร์เฟซสามารถส่งผ่านข้อมูลใด ๆ ที่เกี่ยวข้องกับแอปพลิเคชันได้ ในกรณีของเรา อินเทอร์เฟซจำเป็นต้องเปิดเผยตัวจัดการเหตุการณ์หนึ่งตัว ซึ่งผ่านวันที่สำหรับวันที่กด อินเทอร์เฟซต่อไปนี้ถูกกำหนดใน CalendarView :

 public interface EventHandler { void onDayLongPress(Date date); }

การใช้งานที่จัดเตรียมโดยพาเรนต์สามารถจัดหาให้กับมุมมองปฏิทินผ่าน setEventHandler() นี่คือตัวอย่างการใช้งานจาก `MainActivity.java':

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); HashSet<Date> events = new HashSet<>(); events.add(new Date()); CalendarView cv = ((CalendarView)findViewById(R.id.calendar_view)); cv.updateCalendar(events); // assign event handler cv.setEventHandler(new CalendarView.EventHandler() { @Override public void onDayLongPress(Date date) { // show returned day DateFormat df = SimpleDateFormat.getDateInstance(); Toast.makeText(MainActivity.this, df.format(date), LENGTH_SHORT).show(); } }); }

การกดค้างในหนึ่งวันจะทำให้เกิดเหตุการณ์กดค้างที่ GridView จับและจัดการ และรายงานโดยเรียก onDayLongPress() ในการดำเนินการที่จัดเตรียมไว้ ซึ่งจะแสดงวันที่ของวันที่กดบนหน้าจอ:

ภาพหน้าจอ

อีกวิธีหนึ่งที่ก้าวหน้ากว่าในการจัดการสิ่งนี้คือการใช้ Intents และ BroadcastReceivers ของ Android ซึ่งจะเป็นประโยชน์อย่างยิ่งเมื่อต้องแจ้งองค์ประกอบหลายอย่างเกี่ยวกับกิจกรรมในปฏิทิน ตัวอย่างเช่น หากกดวันในปฏิทินต้องการให้ข้อความแสดงใน Activity และดาวน์โหลดไฟล์โดย Service พื้นหลัง

การใช้วิธีการก่อนหน้านี้จะต้องให้ Activity จัดเตรียม EventHandler ให้กับองค์ประกอบ จัดการเหตุการณ์แล้วส่งต่อไปยัง Service แทนที่จะให้ส่วนประกอบถ่ายทอด Intent และทั้ง Activity และ Service ที่ยอมรับผ่าน BroadcastReceivers ของพวกเขาเอง ไม่เพียงแต่ทำให้ชีวิตง่ายขึ้น แต่ยังช่วยแยก Activity และ Service ที่เป็นปัญหาออกด้วย

บทสรุป

ดูพลังอันยอดเยี่ยมของการปรับแต่ง Android!
ทวีต

นี่คือวิธีสร้างองค์ประกอบที่กำหนดเองของคุณในไม่กี่ขั้นตอนง่ายๆ:

  • สร้างเค้าโครง XML และจัดรูปแบบให้เหมาะกับความต้องการของคุณ
  • สืบทอดคลาสคอมโพเนนต์ของคุณจากคอมโพเนนต์พาเรนต์ที่เหมาะสม ตามเลย์เอาต์ XML ของคุณ
  • เพิ่มตรรกะทางธุรกิจของส่วนประกอบของคุณ
  • ใช้แอตทริบิวต์เพื่อให้ผู้ใช้สามารถปรับเปลี่ยนพฤติกรรมของส่วนประกอบได้
  • เพื่อให้ง่ายต่อการใช้ส่วนประกอบในตัวออกแบบ UI ให้ใช้ isInEditMode() ของ Android

ในบทความนี้ เราได้สร้างมุมมองปฏิทินเป็นตัวอย่าง โดยหลักแล้วเนื่องจากมุมมองปฏิทินหุ้นขาดในหลายๆ ด้าน แต่ไม่จำกัดว่าคุณสามารถสร้างส่วนประกอบประเภทใดได้ คุณสามารถใช้เทคนิคเดียวกันนี้เพื่อสร้างอะไรก็ได้ที่คุณต้องการ ท้องฟ้ามีขีดจำกัด!

ขอบคุณที่อ่านคู่มือนี้ ฉันขอให้คุณโชคดีในความพยายามเขียนโค้ดของคุณ!