Các thuộc tính cùng tên trong attrs.xml cho chế độ xem tùy chỉnh


179

Tôi đang viết một vài khung nhìn tùy chỉnh có chung một số thuộc tính cùng tên. Trong <declare-styleable>phần tương ứng của họ, attrs.xmltôi muốn sử dụng cùng tên cho các thuộc tính:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView1">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>
</resources>

Tôi nhận được một lỗi nói rằng myattr1myattr2đã được xác định. Tôi thấy rằng tôi nên bỏ qua formatthuộc tính cho myattr1myattr2trong MyView2, nhưng nếu tôi làm điều đó, tôi gặp lỗi sau trong bảng điều khiển:

[2010-12-13 23:53:11 - MyProject] ERROR: In <declare-styleable> MyView2, unable to find attribute 

Có cách nào tôi có thể thực hiện điều này, có thể là một số không gian tên (chỉ cần đoán)?

Câu trả lời:


401

Giải pháp: Đơn giản chỉ cần trích xuất các thuộc tính phổ biến từ cả hai chế độ xem và thêm chúng trực tiếp dưới dạng con của <resources>nút:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="myattr1" format="string" />
    <attr name="myattr2" format="dimension" />

    <declare-styleable name="MyView1">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>
</resources>

11
Điều gì xảy ra khi myattr1chuỗi trong MyView1và số nguyên trong MyView2?
foxx1337

4
Tôi không nghĩ vậy, ví dụ: chúng ta có thể có thuộc tính 'định hướng' và đối với một số chế độ xem, đó là 'ngang' / 'dọc' và đối với 'phong cảnh' / 'chân dung' / 'vuông' khác. Theo quan điểm của tôi, đó là một lỗi (hoặc ít nhất là hành vi không nhất quán) trong Android (hãy nhớ rằng: 1. các thuộc tính có thể tạo kiểu luôn bắt đầu bằng tiền tố = tên xem và 2. nếu bạn tạo các dự án thư viện riêng cho các chế độ xem như vậy thì mọi thứ sẽ hoạt động tốt )
se.solovyev

4
Khi tôi làm theo câu trả lời này, tôi nhận được ERROR: In <declare-styleable> com_app_view_widget, unable to find attribute customAttr Đối với tất cả các chế độ xem, tôi cố gắng khai báo cho. Có ý kiến ​​gì không?
Dapp

45
@Google: Thiết kế xảo quyệt
Glenn Bech

6
@ foxx1337 Chỉ cần sử dụng <attr name="myattr1" format="string|integer" />. Làm việc cho tôi.
Mygod

57

Tôi đang đăng câu trả lời này vì giải pháp được đăng ở trên không phù hợp với tôi trong Android Studio. Tôi cần chia sẻ các thuộc tính tùy chỉnh của mình giữa các chế độ xem tùy chỉnh của mình để tôi đã thử giải pháp trên trong Android Studio nhưng không gặp may. Vì vậy, tôi thử nghiệm và đi một cách để làm điều đó. Hy vọng nó có thể giúp ai đó tìm kiếm cùng một vấn đề.

  <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <!-- parent styleable -->
     <declare-styleable name="MyView">
         <attr name="myattr1" format="string" />
         <attr name="myattr2" format="dimension" />
     </declare-styleable>

     <!-- inheriting parent styleable -->
     <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
    <declare-styleable name="MyView1" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myBackgroundColor" format="color"/>
    </declare-styleable>


    <!-- inheriting parent styleable -->
    <!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
    <declare-styleable name="MyView2" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myfont" format="string"/>
        ...
    </declare-styleable>
</resources>

Điều này làm việc cho tôi hoàn toàn. Chúng ta cần làm cho Cha mẹ có thể tạo kiểu và sau đó chúng ta cần kế thừa cha mẹ đó có thể tạo kiểu. Ví dụ, như tôi đã làm ở trên: Tên có thể tạo kiểu cha mẹ MyView và kế thừa tên này với kiểu khác của tôi như MyView1 và MyView2 tương ứng.


1
Điều này làm việc cho tôi. Tôi không thể tìm cách tham chiếu các thuộc tính được trích xuất trong mã từ câu trả lời được chấp nhận.
Nemanja Kovacevic

Hmm..thật là lạ .. giải pháp được chấp nhận dường như đang hoạt động tốt đối với tôi (targetSdkVersion 27). Có lẽ vì các thuộc tính như "văn bản" là phổ biến & có thể đã tồn tại trong một số attrs.xml khác ..?
Aba

Tôi đã thử với một cái tên có lẽ không phổ biến và giải pháp được chấp nhận vẫn hiệu quả với tôi.
Aba

Tôi đồng ý với nhận xét đầu tiên! Không có cách nào để tham chiếu một attr trích xuất từ ​​typedArray. Do đó, bạn cần xác định cha mẹ có thể tạo kiểu
reavcn

để làm việc này, đừng quên giải quyết thuộc tính này ở phụ huynh và không phải ở trẻ em (đối với lớp MyView2đúng : R.styleable.MyView2_myattr1, sai R.styleable.MyView_myattr1:)
cảnh giác

27

Như Priya Singhal đã trả lời, Android Studio yêu cầu các tên thuộc tính chung phải được xác định trong tên kiểu riêng của chúng. Họ không thể ở gốc nữa.

Tuy nhiên, có một vài điều khác cần lưu ý (đó là lý do tại sao tôi cũng đang thêm một câu trả lời):

  • Các kiểu phổ biến không cần được đặt tên giống như một khung nhìn. (Nhờ câu trả lời này đã chỉ ra điều đó.)
  • Bạn không cần phải sử dụng thừa kế với cha mẹ.

Thí dụ

Đây là những gì tôi đã làm trong một dự án gần đây có hai chế độ xem tùy chỉnh mà cả hai đều có chung thuộc tính. Miễn là các chế độ xem tùy chỉnh vẫn có tên cho các thuộc tính và không bao gồm a format, tôi vẫn có thể truy cập chúng như bình thường từ mã.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- common attributes to all custom text based views -->

    <declare-styleable name="TextAttributes">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <!-- custom text views -->

    <declare-styleable name="View1">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Ví dụ hợp lý

Thực tế, tôi thậm chí không cần đặt các thuộc tính dưới một tên tùy chỉnh. Miễn là tôi xác định chúng (cung cấp cho chúng a format) cho ít nhất một chế độ xem tùy chỉnh, tôi có thể sử dụng chúng ở bất cứ đâu (không có format). Vì vậy, điều này cũng hoạt động (và trông sạch hơn):

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="View1">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Tuy nhiên, đối với một dự án lớn, điều này có thể trở nên lộn xộn và việc xác định chúng ở đầu trong một vị trí có thể tốt hơn (như được đề xuất ở đây ).


Điều gì sai với thừa kế? Tôi có hệ thống phân cấp chế độ xem tùy chỉnh mà các kiểu dáng được liên kết không phản ánh mối quan hệ này, điều này chỉ có thể được suy ra trong các định nghĩa kiểu liên quan bằng cách đặt tên cho các quy ước và các mục cụ thể được xác định trong đó (lưu ý rằng một số thuộc về một kiểu dáng và một vài cái khác). Tôi muốn làm cho nó rõ ràng với parentthuộc tính nhưng không thấy nhiều bài viết cho thấy việc sử dụng nó.
samis

@samis, tôi đã không làm việc này trong một thời gian, nhưng tôi không biết có gì sai khi sử dụng parent. Tôi nghĩ rằng tôi chỉ nói rằng nó không cần thiết.
Suragch

Không bắt buộc, tôi chỉ tạo một lớp con khác bao quanh một thuộc tính bổ sung mà tôi không muốn đưa vào lớp cơ sở. Tôi chỉ sử dụng các bình luận và quy ước đặt tên để chỉ ra sự tách biệt.
samis

8

Cảm ơn Lewis Tôi đã có cùng một vấn đề và giải pháp thừa kế của bạn đã cho tôi gợi ý để thực hiện như bên dưới và nó hoạt động tốt. Tôi chỉ khai báo các thuộc tính phổ biến ở trên và viết lại trong phần thân của khai báo kiểu mà không cần định dạng. tôi hi vọng nó giúp ích cho ai đó

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- common attributes -->
     <attr name="myattr1" format="string" />
     <attr name="myattr2" format="dimension" />

 <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
<declare-styleable name="MyView1" >
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myBackgroundColor" format="color"/>
</declare-styleable>

<!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
<declare-styleable name="MyView2" parent="MyView">
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myfont" format="string"/>
    ...
</declare-styleable>


1

Chỉ trong trường hợp ai đó vẫn bị mắc kẹt với vấn đề này sau khi thử giải pháp có sẵn. Tôi bị mắc kẹt với add subtitlethuộc tính với stringđịnh dạng.

Giải pháp của tôi là loại bỏ định dạng.

trước:

<attr name="subtitle" format="string"/>

sau:

<attr name="subtitle"/>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.