วิธีการ: กำหนดธีม (สไตล์) รายการสำหรับวิดเจ็ตที่กำหนดเอง


88

ฉันได้เขียนวิดเจ็ตที่กำหนดเองสำหรับการควบคุมที่เราใช้กันอย่างแพร่หลายในแอปพลิเคชันของเรา คลาสวิดเจ็ตมาจากImageButtonและขยายมันด้วยวิธีง่ายๆสองสามวิธี ฉันได้กำหนดรูปแบบที่สามารถใช้กับวิดเจ็ตได้ตามที่ใช้ แต่ฉันต้องการตั้งค่าผ่านธีม ในR.styleableฉันเห็นคุณลักษณะสไตล์วิดเจ็ตเช่นimageButtonStyleและtextViewStyle. มีวิธีใดบ้างในการสร้างวิดเจ็ตแบบกำหนดเองที่ฉันเขียน?

คำตอบ:


211

ใช่มีทางเดียว:

สมมติว่าคุณมีการประกาศแอตทริบิวต์สำหรับวิดเจ็ตของคุณ (ในattrs.xml):

<declare-styleable name="CustomImageButton">
    <attr name="customAttr" format="string"/>
</declare-styleable>

ประกาศแอตทริบิวต์ที่คุณจะใช้สำหรับการอ้างอิงสไตล์ (ในattrs.xml):

<declare-styleable name="CustomTheme">
    <attr name="customImageButtonStyle" format="reference"/>
</declare-styleable>

ประกาศชุดของค่าแอตทริบิวต์เริ่มต้นสำหรับวิดเจ็ต (ในstyles.xml):

<style name="Widget.ImageButton.Custom" parent="android:style/Widget.ImageButton">
    <item name="customAttr">some value</item>
</style>

ประกาศธีมที่กำหนดเอง (ในthemes.xml):

<style name="Theme.Custom" parent="@android:style/Theme">
    <item name="customImageButtonStyle">@style/Widget.ImageButton.Custom</item>
</style>

ใช้แอ็ตทริบิวต์นี้เป็นอาร์กิวเมนต์ที่สามในคอนสตรัคเตอร์ของวิดเจ็ต (ในCustomImageButton.java):

public class CustomImageButton extends ImageButton {
    private String customAttr;

    public CustomImageButton( Context context ) {
        this( context, null );
    }

    public CustomImageButton( Context context, AttributeSet attrs ) {
        this( context, attrs, R.attr.customImageButtonStyle );
    }

    public CustomImageButton( Context context, AttributeSet attrs,
            int defStyle ) {
        super( context, attrs, defStyle );

        final TypedArray array = context.obtainStyledAttributes( attrs,
            R.styleable.CustomImageButton, defStyle,
            R.style.Widget_ImageButton_Custom ); // see below
        this.customAttr =
            array.getString( R.styleable.CustomImageButton_customAttr, "" );
        array.recycle();
    }
}

ตอนนี้คุณต้องสมัครTheme.Customกับกิจกรรมทั้งหมดที่ใช้CustomImageButton(ใน AndroidManifest.xml):

<activity android:name=".MyActivity" android:theme="@style/Theme.Custom"/>

นั่นคือทั้งหมด ตอนนี้CustomImageButtonพยายามโหลดค่าแอตทริบิวต์เริ่มต้นจากcustomImageButtonStyleแอตทริบิวต์ของธีมปัจจุบัน หากไม่พบแอตทริบิวต์ดังกล่าวในธีมหรือค่าของแอตทริบิวต์จะมีการใช้@nullอาร์กิวเมนต์สุดท้ายobtainStyledAttributes: Widget.ImageButton.Customในกรณีนี้

คุณสามารถเปลี่ยนชื่อของอินสแตนซ์ทั้งหมดและไฟล์ทั้งหมดได้ (ยกเว้นAndroidManifest.xml) แต่จะดีกว่าถ้าใช้หลักการตั้งชื่อ Android


4
มีวิธีทำสิ่งเดียวกันโดยไม่ใช้ธีมหรือไม่? ฉันมีวิดเจ็ตที่กำหนดเอง แต่ฉันต้องการให้ผู้ใช้สามารถใช้วิดเจ็ตเหล่านี้กับธีมที่ต้องการได้ การทำแบบที่คุณโพสต์ต้องการให้ผู้ใช้ใช้ธีมของฉัน
theDazzler

3
@theDazzler: หากคุณหมายถึงไลบรารีที่นักพัฒนาสามารถใช้ได้พวกเขาจะสามารถสร้างธีมของตนเองและระบุสไตล์สำหรับวิดเจ็ตโดยใช้แอตทริบิวต์สไตล์ในธีม ( customImageButtonStyleในคำตอบนี้) นั่นคือวิธีปรับแต่งแถบการทำงานบน Android และถ้าคุณหมายถึงการเปลี่ยนธีมที่รันไทม์ก็ไม่สามารถทำได้ด้วยวิธีนี้
Michael

@ ไมเคิลใช่ฉันหมายถึงห้องสมุดที่นักพัฒนาสามารถใช้ได้ ความคิดเห็นของคุณช่วยแก้ปัญหาของฉันได้ ขอบคุณ!
theDazzler

32
สิ่งที่น่าทึ่งที่สุดเกี่ยวกับทั้งหมดนี้คือใครบางคนใน Google คิดว่ามันโอเค
Glenn Maynard

1
ไม่name="CustomTheme"ในdeclare-styleableแอตทริบิวต์ห่อหุ้มไว้เพื่อวัตถุประสงค์ใด ๆ นั่นเป็นเพียงสำหรับองค์กรเพราะฉันไม่เห็นมันใช้ทุกที่ ฉันสามารถใส่แอตทริบิวต์สไตล์ทั้งหมดของฉันสำหรับวิดเจ็ตต่างๆใน Wrapper เดียวได้หรือไม่
Tenfour04

4

อีกแง่มุมหนึ่งนอกเหนือจากคำตอบที่ยอดเยี่ยมของไมเคิลคือการลบล้างคุณลักษณะที่กำหนดเองในธีม สมมติว่าคุณมีมุมมองแบบกำหนดเองจำนวนหนึ่งซึ่งทั้งหมดอ้างถึงแอตทริบิวต์ที่กำหนดเอง "custom_background"

<declare-styleable name="MyCustomStylables">
    <attr name="custom_background" format="color"/>
</declare-styleable>

ในธีมคุณกำหนดว่าค่าคืออะไร

<style name="MyColorfulTheme" parent="AppTheme">
    <item name="custom_background">#ff0000</item>
</style>

หรือ

<style name="MyBoringTheme" parent="AppTheme">
    <item name="custom_background">#ffffff</item>
</style>

คุณสามารถอ้างถึงแอตทริบิวต์ในรูปแบบ

<style name="MyDefaultLabelStyle" parent="AppTheme">
    <item name="android:background">?background_label</item>
</style>

สังเกตเครื่องหมายคำถามที่ใช้สำหรับอ้างอิงแอตทริบิวต์ android เช่นกัน

?android:attr/colorBackground

อย่างที่คุณส่วนใหญ่สังเกตเห็นคุณสามารถ - และควรใช้การอ้างอิง @color แทนการใช้สีฮาร์ดโค้ด

แล้วทำไมไม่ทำ

<item name="android:background">@color/my_background_color</item>

คุณไม่สามารถเปลี่ยนคำจำกัดความของ "my_background_color" ที่รันไทม์ได้ในขณะที่คุณสามารถเปลี่ยนธีมได้อย่างง่ายดาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.