Tạo Chế độ xem tùy chỉnh bằng cách thổi phồng bố cục?


107

Tôi đang cố gắng tạo một Chế độ xem tùy chỉnh sẽ thay thế một bố cục nhất định mà tôi sử dụng ở nhiều nơi, nhưng tôi đang đấu tranh để làm như vậy.

Về cơ bản, tôi muốn thay thế điều này:

<RelativeLayout
 android:id="@+id/dolphinLine"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
    android:layout_centerInParent="true"
 android:background="@drawable/background_box_light_blue"
 android:padding="10dip"
 android:layout_margin="10dip">
  <TextView
   android:id="@+id/dolphinTitle"
   android:layout_width="200dip"
   android:layout_height="100dip"
   android:layout_alignParentLeft="true"
   android:layout_marginLeft="10dip"
   android:text="@string/my_title"
   android:textSize="30dip"
   android:textStyle="bold"
   android:textColor="#2E4C71"
   android:gravity="center"/>
  <Button
   android:id="@+id/dolphinMinusButton"
   android:layout_width="100dip"
   android:layout_height="100dip"
   android:layout_toRightOf="@+id/dolphinTitle"
   android:layout_marginLeft="30dip"
   android:text="@string/minus_button"
   android:textSize="70dip"
   android:textStyle="bold"
   android:gravity="center"
   android:layout_marginTop="1dip"
   android:background="@drawable/button_blue_square_selector"
   android:textColor="#FFFFFF"
   android:onClick="onClick"/>
  <TextView
   android:id="@+id/dolphinValue"
   android:layout_width="100dip"
   android:layout_height="100dip"
   android:layout_marginLeft="15dip"
   android:background="@android:drawable/editbox_background"
   android:layout_toRightOf="@+id/dolphinMinusButton"
   android:text="0"
   android:textColor="#2E4C71"
   android:textSize="50dip"
   android:gravity="center"
   android:textStyle="bold"
   android:inputType="none"/>
  <Button
   android:id="@+id/dolphinPlusButton"
   android:layout_width="100dip"
   android:layout_height="100dip"
   android:layout_toRightOf="@+id/dolphinValue"
   android:layout_marginLeft="15dip"
   android:text="@string/plus_button"
   android:textSize="70dip"
   android:textStyle="bold"
   android:gravity="center"
   android:layout_marginTop="1dip"
   android:background="@drawable/button_blue_square_selector"
   android:textColor="#FFFFFF"
   android:onClick="onClick"/>
</RelativeLayout>

Bằng cách này:

<view class="com.example.MyQuantityBox"
    android:id="@+id/dolphinBox"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:myCustomAttribute="@string/my_title"/>

Vì vậy, tôi không muốn một bố cục tùy chỉnh, tôi muốn một Chế độ xem tùy chỉnh (không thể có chế độ xem này có con).

Điều duy nhất có thể thay đổi từ phiên bản MyQuantityBox này sang phiên bản khác là tiêu đề. Tôi rất muốn có thể chỉ định điều này trong XML (như tôi làm ở dòng XML cuối cùng)

Tôi có thể làm cái này như thế nào? Tôi có nên đặt RelativeLayout trong tệp XML trong / res / layout và thổi phồng nó trong lớp MyBoxQuantity của mình không? Nếu có, tôi phải làm như thế nào?

Cảm ơn!


Xem "Điều khiển phức hợp" trong Android và liên kết này: stackoverflow.com/questions/1476371/…
greg7gkb

Câu trả lời:


27

Có bạn có thể làm điều này. RelativeLayout, LinearLayout, v.v. là các Chế độ xem vì vậy bố cục tùy chỉnh là một chế độ xem tùy chỉnh. Chỉ cần một cái gì đó để xem xét vì nếu bạn muốn tạo một bố cục tùy chỉnh, bạn có thể.

Những gì bạn muốn làm là tạo Điều khiển phức hợp. Bạn sẽ tạo một lớp con của RelativeLayout, thêm tất cả các thành phần của chúng tôi vào mã (TextView, v.v.) và trong hàm tạo của bạn, bạn có thể đọc các thuộc tính được chuyển vào từ XML. Sau đó, bạn có thể chuyển thuộc tính đó vào TextView tiêu đề của mình.

http://developer.android.com/guide/topics/ui/custom-components.html


130

Hơi cũ, nhưng tôi nghĩ rằng chia sẻ cách tôi sẽ làm điều đó, dựa trên câu trả lời của chubbsondubs: Tôi sử dụng FrameLayout(xem Tài liệu ), vì nó được sử dụng để chứa một chế độ xem duy nhất và thổi phồng nó vào chế độ xem từ xml.

Mã sau:

public class MyView extends FrameLayout {
    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public MyView(Context context) {
        super(context);
        initView();
    }

    private void initView() {
        inflate(getContext(), R.layout.my_view_layout, this);
    }
}

13
Kể từ lớp View có thổi phồng tĩnh () phương pháp không có nhu cầu cho LayoutInflater.from ()
ngoại

1
Đây không phải chỉ là giải pháp của Johannes từ đây: stackoverflow.com/questions/17836695/… Tuy nhiên, điều này làm thổi phồng một bố cục khác bên trong. Vì vậy, nó không thực sự là cách giải quyết tốt nhất mà tôi đoán.
Tobias Reich

3
đúng vậy, nhưng giải pháp của Johannes là từ 7.24.13, và tâm trí là từ 7.1.13 ... Ngoài ra, giải pháp của tôi sử dụng FrameLayout được cho là chỉ chứa một Chế độ xem (như được viết trong tài liệu được tham chiếu trong giải pháp). Vì vậy, thực sự nó được sử dụng làm trình giữ chỗ cho Chế độ xem. Tôi không biết bất kỳ giải pháp nào không sử dụng trình giữ chỗ cho Chế độ xem tăng cao.
Fox

Tôi không hiểu. Phương thức đó (phồng lên) trả về một khung nhìn, được bỏ qua. Có vẻ như bạn cần thêm nó vào chế độ xem hiện tại.
Jeffrey Blattman

1
@Jeffrey Blattman vui lòng kiểm tra phương thức View.inflate , chúng tôi sử dụng phương thức này (chỉ định gốc là thistham số thứ 3)
V1raNi

36

Đây là một bản trình diễn đơn giản để tạo chế độ xem tùy chỉnh (compoundview) bằng cách thổi phồng từ xml

attrs.xml

<resources>

    <declare-styleable name="CustomView">
        <attr format="string" name="text"/>
        <attr format="reference" name="image"/>
    </declare-styleable>
</resources>

CustomView.kt

class CustomView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
        ConstraintLayout(context, attrs, defStyleAttr) {

    init {
        init(attrs)
    }

    private fun init(attrs: AttributeSet?) {
        View.inflate(context, R.layout.custom_layout, this)

        val ta = context.obtainStyledAttributes(attrs, R.styleable.CustomView)
        try {
            val text = ta.getString(R.styleable.CustomView_text)
            val drawableId = ta.getResourceId(R.styleable.CustomView_image, 0)
            if (drawableId != 0) {
                val drawable = AppCompatResources.getDrawable(context, drawableId)
                image_thumb.setImageDrawable(drawable)
            }
            text_title.text = text
        } finally {
            ta.recycle()
        }
    }
}

custom_layout.xml

Chúng ta nên sử dụng mergeở đây thay ConstraintLayoutvì vì

Nếu chúng ta sử dụng ConstraintLayoutở đây, phân cấp bố cục sẽ ConstraintLayout-> ConstraintLayout-> ImageView+ TextView=> chúng ta có 1 phần thừa ConstraintLayout=> không tốt cho hiệu suất

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:parentTag="android.support.constraint.ConstraintLayout">

    <ImageView
        android:id="@+id/image_thumb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:ignore="ContentDescription"
        tools:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/text_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="@id/image_thumb"
        app:layout_constraintStart_toStartOf="@id/image_thumb"
        app:layout_constraintTop_toBottomOf="@id/image_thumb"
        tools:text="Text" />

</merge>

Sử dụng activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <your_package.CustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#f00"
        app:image="@drawable/ic_android"
        app:text="Android" />

    <your_package.CustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#0f0"
        app:image="@drawable/ic_adb"
        app:text="ADB" />

</LinearLayout>

Kết quả

nhập mô tả hình ảnh ở đây

Bản demo trên Github


4
Đây phải là câu trả lời được chấp nhận hoặc được bình chọn nhiều nhất trong chuỗi này vì nó đề cập đến hệ thống phân cấp bố cục không cần thiết.
Farid

15

Sử dụng LayoutInflater như tôi hiển thị bên dưới.

    public View myView() {
        View v; // Creating an instance for View Object
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(R.layout.myview, null);

        TextView text1 = v.findViewById(R.id.dolphinTitle);
        Button btn1 = v.findViewById(R.id.dolphinMinusButton);
        TextView text2 = v.findViewById(R.id.dolphinValue);
        Button btn2 = v.findViewById(R.id.dolphinPlusButton);

        return v;
    }

Tôi đã thử như vậy. nó hoạt động tốt. nhưng, khi tôi nhấp vào btn1, nó sẽ gọi các dịch vụ web và sau khi nhận được phản hồi từ máy chủ, tôi muốn cập nhật một số văn bản ở vị trí cụ thể là text2..bạn có thể giúp gì được không?
harikrishnan

7

Trong thực tế, tôi thấy rằng bạn cần phải cẩn thận một chút, đặc biệt nếu bạn đang sử dụng một chút xml nhiều lần. Ví dụ, giả sử bạn có một bảng mà bạn muốn tạo một hàng bảng cho mỗi mục nhập trong danh sách. Bạn đã thiết lập một số xml:

Trong my_table_row.xml:

<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android" 
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent" android:id="@+id/myTableRow">
    <ImageButton android:src="@android:drawable/ic_menu_delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/rowButton"/>
    <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="TextView" android:id="@+id/rowText"></TextView>
</TableRow>

Sau đó, bạn muốn tạo nó một lần mỗi hàng với một số mã. Nó giả sử rằng bạn đã xác định một myTable TableLayout cha để đính kèm các Hàng vào.

for (int i=0; i<numRows; i++) {
    /*
     * 1. Make the row and attach it to myTable. For some reason this doesn't seem
     * to return the TableRow as you might expect from the xml, so you need to
     * receive the View it returns and then find the TableRow and other items, as
     * per step 2.
     */
    LayoutInflater inflater = (LayoutInflater)getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v =  inflater.inflate(R.layout.my_table_row, myTable, true);

    // 2. Get all the things that we need to refer to to alter in any way.
    TableRow    tr        = (TableRow)    v.findViewById(R.id.profileTableRow);
    ImageButton rowButton = (ImageButton) v.findViewById(R.id.rowButton);
    TextView    rowText   = (TextView)    v.findViewById(R.id.rowText);

    // 3. Configure them out as you need to
    rowText.setText("Text for this row");
    rowButton.setId(i); // So that when it is clicked we know which one has been clicked!
    rowButton.setOnClickListener(this); // See note below ...           

    /*
     * To ensure that when finding views by id on the next time round this
     * loop (or later) gie lots of spurious, unique, ids.
     */
    rowText.setId(1000+i);
    tr.setId(3000+i);
}

Để có một ví dụ đơn giản rõ ràng về cách xử lý rowButton.setOnClickListener (this), hãy xem Onclicklistener để biết nút được tạo theo chương trình .


Xin chào Neil, tôi cũng đã thử. nó hoạt động tốt. nhưng, khi tôi nhấp vào rowButton, nó sẽ gọi các dịch vụ web và sau khi nhận được phản hồi từ máy chủ, tôi muốn cập nhật một số văn bản ở vị trí cụ thể rowText..bạn có thể giúp gì được không?
harikrishnan

cũng xem câu hỏi của tôi. stackoverflow.com/questions/48719970/…
harikrishnan
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.