Intro
แต่น่าเสียดายที่ไม่มีทางไปยังชุดSearchView
ข้อความรูปแบบข้อมูลโดยใช้รูปแบบรูปแบบและมรดกในรูปแบบ XML ที่คุณสามารถทำอะไรกับพื้นหลังของรายการใน ActionBar แบบเลื่อนลง เนื่องจากselectableItemBackground
มีการระบุว่ามีสไตล์ในR.stylable
ขณะที่searchViewTextField
(แอตทริบิวต์ธีมที่เราสนใจ) ไม่ใช่ ดังนั้นเราจึงไม่สามารถเข้าถึงได้อย่างง่ายดายจากภายในทรัพยากร XML (คุณจะได้รับNo resource found that matches the given name: attr 'android:searchViewTextField'
ข้อผิดพลาด)
การตั้งค่าพื้นหลังฟิลด์ข้อความ SearchView จากโค้ด
ดังนั้นวิธีเดียวที่จะแทนที่พื้นหลังของSearchView
ฟิลด์ข้อความได้อย่างถูกต้องคือการเข้าไปในภายในของมันรับการเข้าถึงเพื่อดูที่มีการตั้งค่าพื้นหลังตามsearchViewTextField
และตั้งค่าของเราเอง
หมายเหตุ:โซลูชันด้านล่างขึ้นอยู่กับ id ( android:id/search_plate
) ขององค์ประกอบภายในSearchView
เท่านั้นดังนั้นจึงเป็นเวอร์ชัน SDK ที่เป็นอิสระมากกว่าการส่งผ่านลูก (เช่นใช้searchView.getChildAt(0)
เพื่อไปยังมุมมองที่ถูกต้องภายในSearchView
) แต่ไม่สามารถกันกระสุนได้ โดยเฉพาะอย่างยิ่งหากผู้ผลิตบางรายตัดสินใจที่จะติดตั้งภายในSearchView
และองค์ประกอบที่มี id ที่กล่าวถึงข้างต้นจะไม่สามารถใช้งานได้
ใน SDK พื้นหลังของช่องข้อความในSearchView
จะถูกประกาศผ่านเก้าแพตช์ดังนั้นเราจะทำในลักษณะเดียวกัน คุณสามารถค้นหาเดิมPNGภาพในdrawable-mdpiไดเรกทอรีของAndroid คอมไพล์พื้นที่เก็บข้อมูล เราสนใจภาพสองภาพ หนึ่งสำหรับสถานะเมื่อมีการเลือกฟิลด์ข้อความ (ชื่อtextfield_search_selected_holo_light.9.png ) และอีกรายการหนึ่งสำหรับตำแหน่งที่ไม่ใช่ (ชื่อtextfield_search_default_holo_light.9.png )
น่าเสียดายที่คุณจะต้องสร้างสำเนาของภาพทั้งสองในเครื่องแม้ว่าคุณจะต้องการปรับแต่งเฉพาะสถานะที่โฟกัสก็ตาม นี้เป็นเพราะtextfield_search_default_holo_light
ไม่ได้อยู่ในR.drawable ดังนั้นจึงไม่สามารถเข้าถึงได้โดยง่าย@android:drawable/textfield_search_default_holo_light
ซึ่งสามารถใช้ในตัวเลือกที่แสดงด้านล่างแทนการอ้างอิงในท้องถิ่นที่วาดได้
หมายเหตุ:ฉันใช้ธีม Holo Lightเป็นพื้นฐาน แต่คุณสามารถทำเช่นเดียวกันกับHolo Darkได้ ดูเหมือนว่าจะไม่มีความแตกต่างอย่างแท้จริงในแพตช์ 9 สถานะที่เลือกระหว่างธีมLightและDark อย่างไรก็ตามมีความแตกต่างใน 9 แพตช์สำหรับสถานะเริ่มต้น (ดูLight vs Dark ) ดังนั้นอาจไม่จำเป็นต้องทำสำเนา 9 แพทช์ในเครื่องสำหรับสถานะที่เลือกสำหรับทั้งธีมมืดและสว่าง (สมมติว่าคุณต้องการจัดการทั้งสองอย่างและทำให้ทั้งคู่ดูเหมือนกันในธีม Holo ) เพียงทำสำเนาในเครื่องหนึ่งชุดและใช้ในตัวเลือกที่วาดได้สำหรับทั้งสองธีม
ตอนนี้คุณจะต้องแก้ไขเก้าแพทช์ที่ดาวน์โหลดมาตามความต้องการของคุณ (เช่นเปลี่ยนสีน้ำเงินเป็นสีแดง) คุณสามารถดูไฟล์โดยใช้เครื่องมือวาด 9 แพทช์เพื่อตรวจสอบว่าได้กำหนดไว้อย่างถูกต้องหรือไม่หลังจากการแก้ไขของคุณ
ฉันได้แก้ไขไฟล์โดยใช้GIMPด้วยเครื่องมือดินสอหนึ่งพิกเซล (ค่อนข้างง่าย) แต่คุณอาจใช้เครื่องมือของคุณเอง นี่คือ 9-patch ที่กำหนดเองสำหรับสถานะโฟกัส :
หมายเหตุ:เพื่อความเรียบง่ายฉันใช้เฉพาะภาพสำหรับความหนาแน่นmdpi คุณจะต้องสร้าง9 แพตช์สำหรับความหนาแน่นของหน้าจอหลาย ๆ หน้าจอหากคุณต้องการผลลัพธ์ที่ดีที่สุดบนอุปกรณ์ใด ๆ รูปภาพสำหรับHolo SearchView
สามารถพบได้ในmdpi , hdpiและxhdpi drawable
ตอนนี้เราจะต้องสร้างตัวเลือกที่วาดได้เพื่อให้แสดงภาพที่เหมาะสมตามสถานะการดู สร้างไฟล์ที่res/drawable/texfield_searchview_holo_light.xml
มีเนื้อหาต่อไปนี้:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true"
android:drawable="@drawable/textfield_search_selected_holo_light" />
<item android:drawable="@drawable/textfield_search_default_holo_light" />
</selector>
เราจะใช้ drawable สร้างขึ้นไปยังพื้นหลังที่ตั้งไว้สำหรับLinearLayout
มุมมองที่เก็บข้อมูลข้อความภายในSearchView
- android:id/search_plate
รหัสของมันคือ ต่อไปนี้เป็นวิธีดำเนินการอย่างรวดเร็วในโค้ดเมื่อสร้างเมนูตัวเลือก:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
// Getting SearchView from XML layout by id defined there - my_search_view in this case
SearchView searchView = (SearchView) menu.findItem(R.id.my_search_view).getActionView();
// Getting id for 'search_plate' - the id is part of generate R file,
// so we have to get id on runtime.
int searchPlateId = searchView.getContext().getResources().getIdentifier("android:id/search_plate", null, null);
// Getting the 'search_plate' LinearLayout.
View searchPlate = searchView.findViewById(searchPlateId);
// Setting background of 'search_plate' to earlier defined drawable.
searchPlate.setBackgroundResource(R.drawable.textfield_searchview_holo_light);
return super.onCreateOptionsMenu(menu);
}
}
ผลสุดท้าย
นี่คือภาพหน้าจอของผลลัพธ์สุดท้าย:
ฉันมาถึงจุดนี้ได้อย่างไร
ฉันคิดว่ามันคุ้มค่าที่จะพิจารณาว่าฉันมาถึงจุดนี้ได้อย่างไรเพื่อให้สามารถใช้แนวทางนี้ในการปรับแต่งมุมมองอื่น ๆ
กำลังตรวจสอบเค้าโครงมุมมอง
ฉันได้ตรวจสอบSearchView
ลักษณะของเค้าโครงแล้ว ในSearchView contructorเราสามารถค้นหาเส้นที่ขยายโครงร่าง:
inflater.inflate(R.layout.search_view, this, true);
ตอนนี้เรารู้ว่ารูปแบบที่อยู่ในแฟ้มชื่อSearchView
res/layout/search_view.xml
เมื่อมองเข้าไปในsearch_view.xmlเราจะพบLinearLayout
องค์ประกอบภายใน(พร้อม id search_plate
) ที่มีandroid.widget.SearchView$SearchAutoComplete
อยู่ภายใน (ดูเหมือนช่องข้อความมุมมองการค้นหาของเรา):
<LinearLayout
android:id="@+id/search_plate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:background="?android:attr/searchViewTextField">
ตอนนี้เราได้ตั้งค่าพื้นหลังตามsearchViewTextField
แอตทริบิวต์ของธีมปัจจุบันแล้ว
การตรวจสอบแอตทริบิวต์ (สามารถตั้งค่าได้ง่ายหรือไม่?)
หากต้องการตรวจสอบว่าsearchViewTextField
แอตทริบิวต์มีการตั้งค่าที่เราตรวจสอบความละเอียด / ค่า / themes.xml มีกลุ่มของแอตทริบิวต์ที่เกี่ยวข้องกับSearchView
ค่าเริ่มต้นTheme
:
<style name="Theme">
<!-- (...other attributes present here...) -->
<!-- SearchView attributes -->
<item name="searchDropdownBackground">@android:drawable/spinner_dropdown_background</item>
<item name="searchViewTextField">@drawable/textfield_searchview_holo_dark</item>
<item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_dark</item>
<item name="searchViewCloseIcon">@android:drawable/ic_clear</item>
<item name="searchViewSearchIcon">@android:drawable/ic_search</item>
<item name="searchViewGoIcon">@android:drawable/ic_go</item>
<item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item>
<item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_dark</item>
<item name="searchViewEditQueryBackground">?attr/selectableItemBackground</item>
@drawable/textfield_searchview_holo_dark
เราจะเห็นว่าสำหรับรูปแบบเริ่มต้นมีค่าเป็น สำหรับTheme.Light
ค่าจะถูกตั้งค่าในไฟล์นั้นด้วย
ตอนนี้มันจะดีมากถ้าแอตทริบิวต์นี้สามารถเข้าถึงได้ผ่านรูปแบบRแต่น่าเสียดายที่มันไม่ใช่ สำหรับการเปรียบเทียบให้ดูที่อื่น ๆรูปแบบแอตทริบิวต์ที่มีอยู่ทั้งในthemes.xmlและR.attrเช่นtextAppearanceหรือselectableItemBackground หากsearchViewTextField
มีอยู่ในR.attr
(และR.stylable
) เราสามารถใช้ตัวเลือกที่วาดได้ของเราเมื่อกำหนดธีมสำหรับแอปพลิเคชันทั้งหมดของเราใน XML ตัวอย่างเช่น:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppTheme" parent="android:Theme.Light">
<item name="android:searchViewTextField">@drawable/textfield_searchview_holo_light</item>
</style>
</resources>
ควรแก้ไขอย่างไร
ตอนนี้เรารู้แล้วว่าเราต้องเข้าถึงsearch_plate
รหัส อย่างไรก็ตามเรายังไม่รู้ว่าควรมีลักษณะอย่างไร ในระยะสั้นเราค้นหาภาพวาดใช้เป็นค่าในรูปแบบเริ่มต้น: textfield_searchview_holo_dark.xmlและtextfield_searchview_holo_light.xml เมื่อดูเนื้อหาเราจะเห็นว่าสิ่งที่วาดได้นั้นselector
อ้างอิงสิ่งที่วาดได้อีกสองรายการ (ซึ่งเกิดขึ้นเป็น 9 แพตช์ในภายหลัง) ตามสถานะการดู คุณสามารถค้นหารายการวาด 9 แพตช์แบบรวมได้จาก (เกือบ) ทุกเวอร์ชันของ Android บนandroiddrawables.com
การปรับแต่ง
เรารู้จักเส้นสีน้ำเงินในหนึ่งใน 9 แพตช์ดังนั้นเราจึงสร้างสำเนาในเครื่องและเปลี่ยนสีตามต้องการ