Bir düzeni şişirerek özel bir Görünüm oluşturmak mı?


107

Birden çok yerde kullandığım belirli bir düzenin yerini alacak özel bir Görünüm oluşturmaya çalışıyorum, ancak bunu yapmakta zorlanıyorum.

Temel olarak, bunu değiştirmek istiyorum:

<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>

Bundan:

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

Bu nedenle, özel bir düzen istemiyorum, özel bir Görünüm istiyorum (bu görünümün çocuk sahibi olması mümkün olmamalı).

MyQuantityBox'ın bir örneğinden diğerine değişebilecek tek şey başlıktır. Bunu XML'de belirtebilmeyi çok isterim (son XML satırında yaptığım gibi)

Bunu nasıl yapabilirim? RelativeLayout'u XML dosyasına / res / layout içine koymalı ve MyBoxQuantity sınıfımda şişirmeli miyim? Cevabınız evet ise nasıl yaparım?

Teşekkürler!


Android'de "Bileşik Kontroller" e bakın ve bu bağlantı: stackoverflow.com/questions/1476371/…
greg7gkb

Yanıtlar:


27

Evet, bunu yapabilirsiniz. RelativeLayout, LinearLayout vb. Görünümlerdir, bu nedenle özel bir düzen özel bir görünümdür. Göz önünde bulundurulması gereken bir şey çünkü özel bir düzen oluşturmak istiyorsanız, yapabilirsiniz.

Yapmak istediğiniz bir Bileşik Kontrol oluşturmaktır. RelativeLayout'un bir alt sınıfını oluşturacak, tüm bileşenlerimizi koda ekleyeceksiniz (TextView, vb.) Ve kurucunuzda XML'den aktarılan nitelikleri okuyabilirsiniz. Daha sonra bu niteliği TextView başlığınıza iletebilirsiniz.

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


130

Biraz eski, ama chubbsondubs'un cevabına dayanarak bunu nasıl yapacağımı paylaşmayı düşündüm: Tek bir görünüm içerdiği için kullanıyorum FrameLayout( Belgelere bakın ) ve xml'deki görünümü ona şişirmek için kullanıyorum.

Aşağıdaki kod:

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
Görünüm sınıfı statik inflate sahip olduğundan () yöntemi LayoutInflater.from () için gerek yoktur
uzaktaki

1
Bu sadece Johannes'in buradan çözümü değil mi: stackoverflow.com/questions/17836695/… Yine de bu, içindeki başka bir düzeni şişiriyor. Yani tahmin ettiğim en iyi çözüm bu değil.
Tobias Reich

3
öyle, ancak Johannes çözümü 7.24.13'ten ve zihin 7.1.13'ten ... Ayrıca benim çözümüm, yalnızca bir View içermesi gereken FrameLayout kullanıyor (çözümde atıfta bulunulan belgede yazıldığı gibi). Yani aslında bir Görünüm için yer tutucu olarak kullanılması amaçlanmıştır. Şişirilmiş Görünüm için bir yer tutucu kullanmayan herhangi bir çözüm bilmiyorum.
Fox

Ben anlamadım Bu yöntem (şişirmek), göz ardı edilen bir görünüm döndürür. Mevcut görünüme eklemeniz gerekiyor gibi görünüyor.
Jeffrey Blattman

1
@Jeffrey Blattman lütfen View.inflate yöntemine bakın, bunu kullanıyoruz (kökü şu şekilde belirterek this, 3. parametre)
V1raNi

37

İşte xml'den şişirerek özel görünüm (birleşik görünüm) oluşturmak için basit bir demo

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

Biz gerektiği kullanmak mergeyerine burada ConstraintLayoutçünkü

ConstraintLayoutBurada kullanırsak , düzen hiyerarşisi ConstraintLayout-> ConstraintLayout-> ImageView+ TextView=> olacaktır. 1 yedekimiz var ConstraintLayout=> performans için pek iyi değil

<?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>

Activity_main.xml'i kullanma

<?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>

Sonuç

görüntü açıklamasını buraya girin

Github demosu


5
Gereksiz düzen hiyerarşisinden bahsettiğinden, bu başlıkta kabul edilen veya en çok oylanan cevap bu olmalıdır.
Farid

15

LayoutInflater'ı aşağıda gösterildiği gibi kullanın.

    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;
    }

Ben de aynısını denedim. iyi çalışıyor. ancak, btn1'e tıkladığımda, web hizmetlerini arayacak ve sunucudan yanıt aldıktan sonra, belirli bir metin2 konumunda bazı metni güncellemek istiyorum ... herhangi bir yardım pls?
harikrishnan

7

Pratikte, özellikle tekrar tekrar biraz xml kullanıyorsanız, biraz dikkatli olmanız gerektiğini anladım. Örneğin, listedeki her giriş için bir tablo satırı oluşturmak istediğiniz bir tablonuz olduğunu varsayalım. Bazı xml'ler kurdunuz:

İçinde 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>

Sonra her satırda bir kodla oluşturmak istersiniz. Satırları eklemek için bir üst TableLayout myTable tanımladığınızı varsayar.

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);
}

RowButton.setOnClickListener (bu) işlemeyle ilgili net ve basit bir örnek için, programla oluşturulmuş bir düğme için Onclicklistener'a bakın .


Merhaba Neil, ben de aynısını denedim. iyi çalışıyor. ancak, rowButton'a tıkladığımda, web servislerini çağıracak ve sunucudan yanıt aldıktan sonra, belirli bir satırda bazı metinleri güncellemek istiyorum rowText .. herhangi bir yardım pls?
harikrishnan

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.