ฉันจะประกาศองค์ประกอบ UI ของ Android โดยใช้ XML ได้อย่างไร
ฉันจะประกาศองค์ประกอบ UI ของ Android โดยใช้ XML ได้อย่างไร
คำตอบ:
นดรอยด์สำหรับนักพัฒนาคู่มือการมีส่วนที่เรียกว่าอาคารส่วนประกอบที่กำหนดเอง น่าเสียดายที่การอภิปรายเกี่ยวกับคุณสมบัติของ XMLครอบคลุมเฉพาะการประกาศการควบคุมภายในไฟล์เลย์เอาต์และไม่ได้จัดการค่าภายในการเริ่มต้นคลาสจริง ขั้นตอนดังต่อไปนี้:
values\attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
<attr name="android:text"/>
<attr name="android:textColor"/>
<attr name="extraInformation" format="string" />
</declare-styleable>
</resources>
สังเกตการใช้ชื่อที่ไม่มีเงื่อนไขในdeclare-styleable
แท็ก แอตทริบิวต์ android ที่ไม่ได้มาตรฐานเช่นextraInformation
จำเป็นต้องมีการประกาศประเภทของมัน แท็กที่ประกาศในซูเปอร์คลาสจะพร้อมใช้งานในคลาสย่อยโดยไม่ต้องมีการประกาศใหม่
เนื่องจากมีคอนสตรัคเตอร์สองตัวที่ใช้AttributeSet
สำหรับการกำหนดค่าเริ่มต้นจึงสะดวกในการสร้างวิธีการกำหนดค่าเริ่มต้นแยกต่างหากสำหรับตัวสร้างเพื่อเรียก
private void init(AttributeSet attrs) {
TypedArray a=getContext().obtainStyledAttributes(
attrs,
R.styleable.MyCustomView);
//Use a
Log.i("test",a.getString(
R.styleable.MyCustomView_android_text));
Log.i("test",""+a.getColor(
R.styleable.MyCustomView_android_textColor, Color.BLACK));
Log.i("test",a.getString(
R.styleable.MyCustomView_extraInformation));
//Don't forget this
a.recycle();
}
R.styleable.MyCustomView
เป็นint[]
ทรัพยากรที่สร้างอัตโนมัติโดยที่องค์ประกอบแต่ละรายการเป็น ID ของแอตทริบิวต์ แอททริบิวถูกสร้างขึ้นสำหรับแต่ละคุณสมบัติใน XML โดยการผนวกชื่อแอ็ตทริบิวต์กับชื่อองค์ประกอบ ตัวอย่างเช่นR.styleable.MyCustomView_android_text
มีแอตทริบิวต์สำหรับandroid_text
MyCustomView
คุณสมบัตินั้นสามารถดึงจากการTypedArray
ใช้get
ฟังก์ชั่นต่างๆ หากไม่ได้กำหนดแอตทริบิวต์ในที่กำหนดใน XML ดังนั้นnull
จะส่งคืน ยกเว้นแน่นอนถ้าประเภทส่งคืนเป็นแบบดั้งเดิมซึ่งในกรณีนี้อาร์กิวเมนต์ที่สองจะถูกส่งกลับ
หากคุณไม่ต้องการที่จะดึงข้อมูลทั้งหมดของคุณลักษณะที่มันเป็นไปได้ที่จะสร้างอาร์เรย์นี้ manually.The ID สำหรับหุ่นยนต์คุณลักษณะมาตรฐานจะรวมอยู่ในขณะแอตทริบิวต์สำหรับโครงการนี้อยู่ในandroid.R.attr
R.attr
int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};
โปรดทราบว่าคุณควรจะไม่ได้ใช้อะไรในการandroid.R.styleable
ตามหัวข้อนี้มันอาจมีการเปลี่ยนแปลงในอนาคต มันยังอยู่ในเอกสารว่าการดูค่าคงที่ทั้งหมดเหล่านี้ในที่เดียวมีประโยชน์
layout\main.xml
รวมการประกาศ namespace xmlns:app="http://schemas.android.com/apk/res-auto"
ในองค์ประกอบ xml ระดับบนสุด Namespaces จัดเตรียมวิธีการหลีกเลี่ยงความขัดแย้งที่บางครั้งเกิดขึ้นเมื่อ schema ที่แตกต่างกันใช้ชื่อองค์ประกอบเดียวกัน (ดูบทความนี้สำหรับข้อมูลเพิ่มเติม) URL เป็นเพียงรูปแบบของการระบุสกีมาที่ไม่ซ้ำกันจริง ๆ แล้วไม่มีอะไรที่จะต้องโฮสต์ใน URLนั้น หากสิ่งนี้ไม่ปรากฏว่ากำลังทำอะไรอยู่นั่นอาจเป็นเพราะคุณไม่จำเป็นต้องเพิ่มคำนำหน้าเนมสเปซเว้นแต่คุณจะต้องแก้ไขข้อขัดแย้ง
<com.mycompany.projectname.MyCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:text="Test text"
android:textColor="#FFFFFF"
app:extraInformation="My extra information"
/>
อ้างอิงมุมมองที่กำหนดเองโดยใช้ชื่อแบบเต็ม
หากคุณต้องการตัวอย่างที่สมบูรณ์ให้ดูที่ตัวอย่างมุมมองฉลาก Android
TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
CharSequences=a.getString(R.styleable.LabelView_text);
<declare-styleable name="LabelView">
<attr name="text"format="string"/>
<attr name="textColor"format="color"/>
<attr name="textSize"format="dimension"/>
</declare-styleable>
<com.example.android.apis.view.LabelView
android:background="@drawable/blue"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:text="Blue" app:textSize="20dp"/>
สิ่งนี้มีอยู่ในLinearLayout
พร้อมกับแอตทริบิวต์ namespace:xmlns:app="http://schemas.android.com/apk/res-auto"
การอ้างอิงที่ดี ขอบคุณ! นอกเหนือไปจากมัน
หากคุณมีโครงการห้องสมุดรวมอยู่ด้วยซึ่งได้ประกาศแอตทริบิวต์ที่กำหนดเองสำหรับมุมมองที่กำหนดเองคุณจะต้องประกาศเนมสเปซโครงการของคุณไม่ใช่ของโครงการ เช่น:
ระบุว่าไลบรารีมีแพ็คเกจ "com.example.library.customview" และโครงการทำงานมีแพ็คเกจ "com.example.customview" จากนั้น:
จะไม่ทำงาน (แสดงข้อผิดพลาด "ข้อผิดพลาด: ไม่พบตัวระบุทรัพยากรสำหรับแอตทริบิวต์ 'newAttr' ในแพ็คเกจ 'com.example.library.customview'"):
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
android:id="@+id/myView"
app:newAttr="value" />
จะทำงาน:
<com.library.CustomView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.customview"
android:id="@+id/myView"
app:newAttr="value" />
xmlns:app="http://schemas.android.com/apk/res-auto"
โปรดดูความคิดเห็นที่ 57 ในcode.google.com/p/android/issues/detail?id=9656
Suspicious namespace: Did you mean http://schemas.android.com/apk/res-auto
res-auto
เนื่องจากเรากำลังใช้ Android Studio และ Gradle มิฉะนั้น (เช่นบางรุ่น Eclipse) lib/[your package name]
ก็มักจะจบลงใน iehttp://schemas.android.com/apk/lib/[your package name]
นอกเหนือจากคำตอบที่โหวตมากที่สุด
ฉันต้องการเพิ่มคำบางคำเกี่ยวกับการใช้งาน getStyledAttributes () เมื่อเราสร้างมุมมองที่กำหนดเองโดยใช้แอตทริบิวต์ android: xxx prdefined โดยเฉพาะอย่างยิ่งเมื่อเราใช้ TextAppearance
ตามที่กล่าวไว้ใน "2. การสร้างตัวสร้าง" มุมมองที่กำหนดเองจะได้รับ AttributeSet ในการสร้าง การใช้งานหลักที่เราเห็นในซอร์สโค้ดของ TextView (API 16)
final Resources.Theme theme = context.getTheme();
// TextAppearance is inspected first, but let observe it later
TypedArray a = theme.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TextView, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++)
{
int attr = a.getIndex(i);
// huge switch with pattern value=a.getXXX(attr) <=> a.getXXX(a.getIndex(i))
}
a.recycle();
เราเห็นอะไรที่นี่?
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
ชุดคุณสมบัติจะถูกประมวลผลโดยธีมตามเอกสาร ค่าคุณสมบัติเป็นขั้นตอนที่รวบรวมโดยขั้นตอน แอ็ตทริบิวต์แรกถูกเติมจากธีมจากนั้นค่าจะถูกแทนที่ด้วยค่าจากสไตล์และค่าที่แน่นอนที่สุดจาก XML สำหรับอินสแตนซ์มุมมองพิเศษจะแทนที่ผู้อื่น
อาร์เรย์ของแอตทริบิวต์ที่ร้องขอ - com.android.internal.R.styleable.TextView
มันเป็นอาร์เรย์คงที่ปกติ หากเราร้องขอคุณสมบัติมาตรฐานเราสามารถสร้างอาร์เรย์นี้ได้ด้วยตนเอง
สิ่งที่ไม่ได้กล่าวถึงในเอกสารประกอบ - ลำดับของผลลัพธ์องค์ประกอบ TypedArray
เมื่อประกาศมุมมองที่กำหนดเองใน attrs.xml ค่าคงที่พิเศษสำหรับดัชนีแอตทริบิวต์จะถูกสร้างขึ้น และเราสามารถดึงค่าด้วยวิธีนี้: a.getString(R.styleable.MyCustomView_android_text)
. แต่สำหรับคู่มือint[]
ไม่มีค่าคงที่ ฉันคิดว่า getXXXValue (arrayIndex) จะทำงานได้ดี
และคำถามอื่นคือ: "เราจะเปลี่ยนค่าคงที่ภายในและขอคุณลักษณะมาตรฐานได้อย่างไร" เราสามารถใช้ค่า android.R.attr. *
ดังนั้นหากเราต้องการใช้แอตทริบิวต์ TextAppearance มาตรฐานในมุมมองที่กำหนดเองและอ่านค่าใน Constructor เราสามารถแก้ไขโค้ดจาก TextView ด้วยวิธีนี้:
ColorStateList textColorApp = null;
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;
Resources.Theme theme = context.getTheme();
TypedArray a = theme.obtainStyledAttributes(attrs, R.styleable.CustomLabel, defStyle, 0);
TypedArray appearance = null;
int apResourceId = a.getResourceId(R.styleable.CustomLabel_android_textAppearance, -1);
a.recycle();
if (apResourceId != -1)
{
appearance =
theme.obtainStyledAttributes(apResourceId, new int[] { android.R.attr.textColor, android.R.attr.textSize,
android.R.attr.typeface, android.R.attr.textStyle });
}
if (appearance != null)
{
textColorApp = appearance.getColorStateList(0);
textSize = appearance.getDimensionPixelSize(1, textSize);
typefaceIndex = appearance.getInt(2, -1);
styleIndex = appearance.getInt(3, -1);
appearance.recycle();
}
ตำแหน่งที่ CustomLabel กำหนดไว้:
<declare-styleable name="CustomLabel">
<!-- Label text. -->
<attr name="android:text" />
<!-- Label text color. -->
<attr name="android:textColor" />
<!-- Combined text appearance properties. -->
<attr name="android:textAppearance" />
</declare-styleable>
อาจเป็นเพราะฉันเข้าใจผิดบางอย่าง แต่เอกสาร Android เกี่ยวกับ getStyledAttributes () นั้นแย่มาก
ในขณะเดียวกันเราก็สามารถขยายองค์ประกอบ UI มาตรฐานโดยใช้คุณสมบัติที่ประกาศไว้ทั้งหมด วิธีการนี้ไม่ดีนักเนื่องจาก TextView เช่นประกาศคุณสมบัติมากมาย และมันจะเป็นไปไม่ได้ที่จะใช้ฟังก์ชั่นเต็มรูปแบบใน overriden onMeasure () และ onDraw ()
แต่เราสามารถเสียสละองค์ประกอบที่กำหนดเองในเชิงทฤษฎีได้ พูดว่า "ฉันรู้แน่ชัดว่าฟีเจอร์ใดที่ฉันจะใช้" และไม่แชร์รหัสกับใคร
CustomComponent(Context, AttributeSet, defStyle)
แล้วเราสามารถใช้คอนสตรัค หลังจากการโทรsuper(...)
เราจะมีการแยกวิเคราะห์คุณลักษณะและให้บริการผ่านวิธีการทะเยอทะยาน
ดูเหมือนว่า Google ได้อัปเดตหน้าผู้พัฒนาและเพิ่มการฝึกอบรมที่นั่น
หนึ่งในนั้นเกี่ยวข้องกับการสร้างมุมมองที่กำหนดเองและสามารถดูได้ที่นี่
ขอบคุณมากสำหรับคำตอบแรก
สำหรับฉันฉันมีปัญหาเดียวกับมัน เมื่อขยายมุมมองของฉันฉันมีข้อผิดพลาด: java.lang.NoSuchMethodException: MyView (บริบทคุณลักษณะ)
ฉันแก้ไขมันโดยการสร้างนวกรรมิกใหม่:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// some code
}
หวังว่านี่จะช่วยได้!
คุณสามารถรวมไฟล์เลย์เอาต์ใด ๆ ในไฟล์เลย์เอาต์อื่น ๆ เป็น -
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="30dp" >
<include
android:id="@+id/frnd_img_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_imagefile"/>
<include
android:id="@+id/frnd_video_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
layout="@layout/include_video_lay" />
<ImageView
android:id="@+id/downloadbtn"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:src="@drawable/plus"/>
</RelativeLayout>
นี่คือไฟล์เลย์เอาต์ในแท็กรวมเป็นไฟล์เลย์เอาต์. xml อื่น ๆ ในโฟลเดอร์ res เดียวกัน