Tôi cần thực hiện các thuộc tính của riêng mình như trong com.android.R.attr
Không tìm thấy gì trong tài liệu chính thức nên tôi cần thông tin về cách xác định các attrs này và cách sử dụng chúng từ mã của tôi.
Tôi cần thực hiện các thuộc tính của riêng mình như trong com.android.R.attr
Không tìm thấy gì trong tài liệu chính thức nên tôi cần thông tin về cách xác định các attrs này và cách sử dụng chúng từ mã của tôi.
Câu trả lời:
Hiện tại tài liệu tốt nhất là nguồn. Bạn có thể xem nó ở đây (attrs.xml) .
Bạn có thể xác định các thuộc tính trong <resources>
phần tử trên cùng hoặc bên trong một <declare-styleable>
phần tử. Nếu tôi sẽ sử dụng một attr ở nhiều nơi, tôi sẽ đặt nó vào phần tử gốc. Lưu ý, tất cả các thuộc tính chia sẻ cùng một không gian tên toàn cầu. Điều đó có nghĩa là ngay cả khi bạn tạo một thuộc tính mới bên trong một <declare-styleable>
phần tử, nó có thể được sử dụng bên ngoài nó và bạn không thể tạo một thuộc tính khác có cùng tên của một loại khác.
Một <attr>
phần tử có hai thuộc tính xml name
và format
. name
cho phép bạn gọi nó là một cái gì đó và đây là cách bạn kết thúc đề cập đến nó trong mã, ví dụ , R.attr.my_attribute
. Các format
thuộc tính có thể có giá trị khác nhau tùy thuộc vào 'loại' của thuộc tính mà bạn muốn.
Bạn có thể đặt định dạng thành nhiều loại bằng cách sử dụng |
, ví dụ : format="reference|color"
.
enum
các thuộc tính có thể được định nghĩa như sau:
<attr name="my_enum_attr">
<enum name="value1" value="1" />
<enum name="value2" value="2" />
</attr>
flag
các thuộc tính tương tự nhau ngoại trừ các giá trị cần được xác định để chúng có thể được ghép với nhau:
<attr name="my_flag_attr">
<flag name="fuzzy" value="0x01" />
<flag name="cold" value="0x02" />
</attr>
Ngoài các thuộc tính còn có <declare-styleable>
yếu tố. Điều này cho phép bạn xác định các thuộc tính mà chế độ xem tùy chỉnh có thể sử dụng. Bạn làm điều này bằng cách chỉ định một <attr>
phần tử, nếu nó được xác định trước đó, bạn không chỉ định format
. Nếu bạn muốn sử dụng lại một attr android, ví dụ: android: vity, thì bạn có thể làm điều đó trong name
, như sau.
Một ví dụ về chế độ xem tùy chỉnh <declare-styleable>
:
<declare-styleable name="MyCustomView">
<attr name="my_custom_attribute" />
<attr name="android:gravity" />
</declare-styleable>
Khi xác định các thuộc tính tùy chỉnh của bạn trong XML trên chế độ xem tùy chỉnh của bạn, bạn cần thực hiện một số điều. Trước tiên, bạn phải khai báo một không gian tên để tìm thuộc tính của bạn. Bạn làm điều này trên các yếu tố bố trí gốc. Thông thường chỉ có xmlns:android="http://schemas.android.com/apk/res/android"
. Bây giờ bạn cũng phải thêm xmlns:whatever="http://schemas.android.com/apk/res-auto"
.
Thí dụ:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:whatever="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<org.example.mypackage.MyCustomView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
whatever:my_custom_attribute="Hello, world!" />
</LinearLayout>
Cuối cùng, để truy cập thuộc tính tùy chỉnh đó, bạn thường làm như vậy trong hàm tạo của chế độ xem tùy chỉnh của mình như sau.
public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyle, 0);
String str = a.getString(R.styleable.MyCustomView_my_custom_attribute);
//do something with str
a.recycle();
}
Kết thúc. :)
View
: github.com/commonsguy/cw-advandroid/tree/master/Views/ trộm
xmlns:my="http://schemas.android.com/apk/lib/my.namespace"
mẹo - Nó dường như hoạt động nếu bạn sử dụng - không sao chép attrs.xml. Lưu ý đường dẫn URI không gian tên phải là / apk / * lib * không / apk / res.
apk/lib
thủ thuật không hoạt động với tôi về các thuộc tính tùy chỉnh với định dạng tham chiếu từ dự án thư viện. Những gì đã làm việc là sử dụng apk/res-auto
, như được đề xuất trong stackoverflow.com/a/13420366/22904 ngay bên dưới và cả trong stackoverflow.com/a/10217752
enum
và flag
: cái trước cho phép chúng ta chọn một và chỉ một giá trị, cái sau cho phép chúng ta kết hợp nhiều giá trị. Tôi đã viết lên một câu trả lời dài hơn trong một câu hỏi tương tự ở đây , và bây giờ tìm thấy câu hỏi này tôi đã tìm ra tôi liên kết đến đó.
a.recycle()
ở đây rất quan trọng để giải phóng bộ nhớ
Câu trả lời của Qberticus là tốt, nhưng thiếu một chi tiết hữu ích. Nếu bạn đang thực hiện những điều này trong một thư viện thay thế:
xmlns:whatever="http://schemas.android.com/apk/res/org.example.mypackage"
với:
xmlns:whatever="http://schemas.android.com/apk/res-auto"
Nếu không, ứng dụng sử dụng thư viện sẽ có lỗi thời gian chạy.
Câu trả lời ở trên bao gồm mọi thứ rất chi tiết, ngoài một vài điều.
Đầu tiên, nếu không có kiểu, thì (Context context, AttributeSet attrs)
chữ ký phương thức sẽ được sử dụng để khởi tạo ưu tiên. Trong trường hợp này, chỉ cần sử dụng context.obtainStyledAttributes(attrs, R.styleable.MyCustomView)
để lấy TypedArray.
Thứ hai, nó không bao gồm làm thế nào để đối phó với tài nguyên plaurals (chuỗi số lượng). Chúng không thể được xử lý bằng TypedArray. Đây là đoạn mã từ SeekBarPreference của tôi, đặt tóm tắt về định dạng ưu tiên định dạng giá trị của nó theo giá trị của ưu tiên. Nếu xml cho tùy chọn đặt android: tóm tắt thành chuỗi văn bản hoặc chuỗi nối lại giá trị của tùy chọn được định dạng thành chuỗi (cần có% d trong đó, để chọn giá trị). Nếu android: Tóm tắt được đặt thành tài nguyên plaurals, thì đó được sử dụng để định dạng kết quả.
// Use your own name space if not using an android resource.
final static private String ANDROID_NS =
"http://schemas.android.com/apk/res/android";
private int pluralResource;
private Resources resources;
private String summary;
public SeekBarPreference(Context context, AttributeSet attrs) {
// ...
TypedArray attributes = context.obtainStyledAttributes(
attrs, R.styleable.SeekBarPreference);
pluralResource = attrs.getAttributeResourceValue(ANDROID_NS, "summary", 0);
if (pluralResource != 0) {
if (! resources.getResourceTypeName(pluralResource).equals("plurals")) {
pluralResource = 0;
}
}
if (pluralResource == 0) {
summary = attributes.getString(
R.styleable.SeekBarPreference_android_summary);
}
attributes.recycle();
}
@Override
public CharSequence getSummary() {
int value = getPersistedInt(defaultValue);
if (pluralResource != 0) {
return resources.getQuantityString(pluralResource, value, value);
}
return (summary == null) ? null : String.format(summary, value);
}
notifyChanged()
theo onDialogClosed
phương thức của tùy chọn .Cách tiếp cận truyền thống có đầy đủ mã soạn sẵn và xử lý tài nguyên vụng về. Đó là lý do tại sao tôi tạo ra khung Spylass . Để giải thích cách thức hoạt động của nó, đây là một ví dụ cho thấy cách tạo chế độ xem tùy chỉnh hiển thị tiêu đề Chuỗi.
Bước 1: Tạo một lớp xem tùy chỉnh.
public class CustomView extends FrameLayout {
private TextView titleView;
public CustomView(Context context) {
super(context);
init(null, 0, 0);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0, 0);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, defStyleAttr, 0);
}
@RequiresApi(21)
public CustomView(
Context context,
AttributeSet attrs,
int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs, defStyleAttr, defStyleRes);
}
public void setTitle(String title) {
titleView.setText(title);
}
private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
inflate(getContext(), R.layout.custom_view, this);
titleView = findViewById(R.id.title_view);
}
}
Bước 2: Xác định một thuộc tính chuỗi trong values/attrs.xml
tệp tài nguyên:
<resources>
<declare-styleable name="CustomView">
<attr name="title" format="string"/>
</declare-styleable>
</resources>
Bước 3: Áp dụng @StringHandler
chú thích cho setTitle
phương thức để báo cho khung Spylass định tuyến giá trị thuộc tính đến phương thức này khi chế độ xem bị thổi phồng.
@HandlesString(attributeId = R.styleable.CustomView_title)
public void setTitle(String title) {
titleView.setText(title);
}
Bây giờ lớp của bạn có chú thích Spylass, khung Spylass sẽ phát hiện nó vào thời gian biên dịch và tự động tạo CustomView_SpyglassCompanion
lớp.
Bước 4: Sử dụng lớp được tạo trong init
phương thức của khung nhìn tùy chỉnh :
private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
inflate(getContext(), R.layout.custom_view, this);
titleView = findViewById(R.id.title_view);
CustomView_SpyglassCompanion
.builder()
.withTarget(this)
.withContext(getContext())
.withAttributeSet(attrs)
.withDefaultStyleAttribute(defStyleAttr)
.withDefaultStyleResource(defStyleRes)
.build()
.callTargetMethodsNow();
}
Đó là nó. Bây giờ khi bạn khởi tạo lớp từ XML, trình đồng hành Spylass sẽ diễn giải các thuộc tính và thực hiện cuộc gọi phương thức cần thiết. Ví dụ, nếu chúng ta thổi phồng bố cục sau thì setTitle
sẽ được gọi với "Hello, World!"
tư cách là đối số.
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:width="match_parent"
android:height="match_parent">
<com.example.CustomView
android:width="match_parent"
android:height="match_parent"
app:title="Hello, World!"/>
</FrameLayout>
Khung không giới hạn đối với tài nguyên chuỗi có nhiều chú thích khác nhau để xử lý các loại tài nguyên khác. Nó cũng có các chú thích để xác định các giá trị mặc định và để chuyển các giá trị giữ chỗ nếu các phương thức của bạn có nhiều tham số.
Hãy xem repo Github để biết thêm thông tin và ví dụ.
android:title="@{"Hello, world!"}"
.
nếu bạn bỏ qua format
thuộc tính từ attr
phần tử, bạn có thể sử dụng nó để tham chiếu một lớp từ các bố cục XML.
Refactor > Rename
làmFind Usages
làmkhông chỉ định một format
thuộc tính trong ... / src / main / res / value / attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
....
<attr name="give_me_a_class"/>
....
</declare-styleable>
</resources>
sử dụng nó trong một số tệp bố cục ... / src / main / res / layout / Activity__main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<SomeLayout
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- make sure to use $ dollar signs for nested classes -->
<MyCustomView
app:give_me_a_class="class.type.name.Outer$Nested/>
<MyCustomView
app:give_me_a_class="class.type.name.AnotherClass/>
</SomeLayout>
phân tích lớp trong mã khởi tạo chế độ xem của bạn ... / src / main / java /.../ MyCustomView.kt
class MyCustomView(
context:Context,
attrs:AttributeSet)
:View(context,attrs)
{
// parse XML attributes
....
private val giveMeAClass:SomeCustomInterface
init
{
context.theme.obtainStyledAttributes(attrs,R.styleable.ColorPreference,0,0).apply()
{
try
{
// very important to use the class loader from the passed-in context
giveMeAClass = context::class.java.classLoader!!
.loadClass(getString(R.styleable.MyCustomView_give_me_a_class))
.newInstance() // instantiate using 0-args constructor
.let {it as SomeCustomInterface}
}
finally
{
recycle()
}
}
}