建立複合檢視
阿化合物檢視是,會被視為由周圍的程式程式碼的單個檢視的自定義 ViewGroup
。這樣的 ViewGroup 在類似 DDD 的設計中非常有用,因為它可以對應於聚合,在本例中是一個聯絡。它可以在顯示聯絡人的任何地方重複使用。
這意味著周圍的控制器程式碼,Activity,Fragment 或 Adapter,可以簡單地將資料物件傳遞給檢視,而無需將其分成許多不同的 UI 小部件。
這有助於程式碼重用,並根據 SOLID 原則提供更好的設計。
佈局 XML
這通常是你開始的地方。你有一些 XML,你發現自己正在重用,也許是作為一個 <include/>
。將其解壓縮到一個單獨的 XML 檔案中,並將根標記包裝在 <merge>
元素中:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/photo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentRight="true" />
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/photo" />
<TextView
android:id="@+id/phone_number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:layout_toLeftOf="@id/photo" />
</merge>
這個 XML 檔案在 Android Studio 的佈局編輯器中保持完美。你可以像對待任何其他佈局一樣對待它。
複合 ViewGroup
獲得 XML 檔案後,建立自定義檢視組。
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.ImageView;
import android.widget.TextView;
import myapp.R;
/**
* A compound view to show contacts.
*
* This class can be put into an XML layout or instantiated programmatically, it
* will work correctly either way.
*/
public class ContactView extends RelativeLayout {
// This class extends RelativeLayout because that comes with an automatic
// (MATCH_PARENT, MATCH_PARENT) layout for its child item. You can extend
// the raw android.view.ViewGroup class if you want more control. See the
// note in the layout XML why you wouldn't want to extend a complex view
// such as RelativeLayout.
// 1. Implement superclass constructors.
public ContactView(Context context) {
super(context);
init(context, null);
}
// two extra constructors left out to keep the example shorter
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ContactView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
// 2. Initialize the view by inflating an XML using `this` as parent
private TextView mName;
private TextView mPhoneNumber;
private ImageView mPhoto;
private void init(Context context, AttributeSet attrs) {
LayoutInflater.from(context).inflate(R.layout.contact_view, this, true);
mName = (TextView) findViewById(R.id.name);
mPhoneNumber = (TextView) findViewById(R.id.phone_number);
mPhoto = (ImageView) findViewById(R.id.photo);
}
// 3. Define a setter that's expressed in your domain model. This is what the example is
// all about. All controller code can just invoke this setter instead of fiddling with
// lots of strings, visibility options, colors, animations, etc. If you don't use a
// custom view, this code will usually end up in a static helper method (bad) or copies
// of this code will be copy-pasted all over the place (worse).
public void setContact(Contact contact) {
mName.setText(contact.getName());
mPhoneNumber.setText(contact.getPhoneNumber());
if (contact.hasPhoto()) {
mPhoto.setVisibility(View.VISIBLE);
mPhoto.setImageBitmap(contact.getPhoto());
} else {
mPhoto.setVisibility(View.GONE);
}
}
}
你可以在 init(Context, AttributeSet)
方法中讀取任何自定義 XML 屬性,如向檢視新增屬性中所述 。
有了這些部分,你可以在你的應用程式中使用它。
XML 中的用法
這是一個示例 fragment_contact_info.xml
,它說明了如何將單個 ContactView 放在訊息列表之上:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- The compound view becomes like any other view XML element -->
<myapp.ContactView
android:id="@+id/contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/message_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
程式碼中的用法
這是一個顯示聯絡人列表的示例 RecyclerView.Adapter
。這個例子說明了當控制器程式碼完全沒有 View 操作時,控制器程式碼會變得多清晰。
package myapp;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
public class ContactsAdapter extends RecyclerView.Adapter<ContactsViewHolder> {
private final Context context;
public ContactsAdapter(final Context context) {
this.context = context;
}
@Override
public ContactsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ContactView v = new ContactView(context); // <--- this
return new ContactsViewHolder(v);
}
@Override
public void onBindViewHolder(ContactsViewHolder holder, int position) {
Contact contact = this.getItem(position);
holder.setContact(contact); // <--- this
}
static class ContactsViewHolder extends RecyclerView.ViewHolder {
public ContactsViewHolder(ContactView itemView) {
super(itemView);
}
public void setContact(Contact contact) {
((ContactView) itemView).setContact(contact); // <--- this
}
}
}