簡體   English   中英

使用新適配器更新 recyclerview

[英]Update recyclerview with new adapter

我有一個片段,頂部有一個 Searchview,在這個片段下面我顯示了一個帶有 10 個調用的通話記錄。 為了顯示通話記錄,我使用帶有卡片的 recyclerview。 這種行為工作正常,但現在我想實現別的東西。

如果我在 Searchview 中搜索一個名字,我想做一些事情,比如當結果列表更新時顯示與聯系人列表的巧合。 這是,我需要重用 recyclerview,但此時,我將顯示與聯系人列表的巧合,而不是通話記錄。

我使用了此處找到的代碼,但無法正常工作。 我正在做一些測試,看看有什么問題,我發現我無法重用 recyclerview。

首先,我這樣做是為了顯示通話記錄:

mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
mLogAdapter = new LogAdapter(DisplayCallLog());
mRecyclerView.setAdapter(mLogAdapter);

當搜索視圖更新時,我正在嘗試僅顯示聯系人列表以驗證這是否有效:

public boolean onQueryTextChange(String query) {
    mContactAdapter = new ContactAdapter(ContactsList());
    mRecyclerView.swapAdapter(mContactAdapter, true);
    //final List<ContactInfo> filteredModelList = filter(ContactsList(), query);
    //mContactAdapter.animateTo(filteredModelList);
    //mRecyclerView.scrollToPosition(0);
    return true;
}

但是我無法在同一個回收站視圖上顯示聯系人列表。


編輯 1 -> 評論

我試過在啟動時加載聯系人列表而不是日志列表,但它也沒有加載它。 也許問題是聯系人列表太長?


編輯 2 -> 添加了大量代碼

1)設置搜索視圖

我沒有在操作欄中添加搜索視圖,而是使用卡片視圖來包含它。 這是phone_layout.xml

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="60dp">
    <android.support.v7.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="4dp"
        card_view:cardElevation="4dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="80dp"
        android:layout_marginRight="80dp">
        <android.support.v7.widget.SearchView
            android:id="@+id/dialpad_searchview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/transparent"
            android:textSize="18sp"
            app:queryHint="@string/enter_phone_number"
            app:iconifiedByDefault="false"
            android:imeOptions="flagNoFullscreen"/>
    </android.support.v7.widget.CardView>
</LinearLayout>
<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="5dp"
    android:layout_marginLeft="80dp"
    android:layout_marginRight="80dp"/>

2)設置適配器

首先我定義模型類ContactInfo 這對於展位使用通話記錄和聯系人巧合是相同的。

public class ContactInfo {

public int id;
public String name;
public String number;
public String type;
public int logType;

public static final String ID_PREFIX = "ID_";
public static final String NUMBER_PREFIX = "Name_";
public static final String NAME_PREFIX = "Number_";
public static final String TYPE_PREFIX = "Type_";

public String getContactName() {
    return name;
}
public String getContactNumber() {
    return number;
}

對於展位, ContactViewHolder也是相同的。

public class ContactViewHolder extends RecyclerView.ViewHolder {
protected TextView vName;
protected TextView vType;
protected ImageView vPic;

public ContactViewHolder(View v) {
    super(v);
    vName =  (TextView) v.findViewById(R.id.contactname);
    vType = (TextView)  v.findViewById(R.id.contacttype);
    vPic = (ImageView)  v.findViewById(R.id.contactpic);
}

現在,每種用途的不同之處在於布局和適配器。 從通話記錄開始,這里是phone_calllog_card.xml

<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
android:layout_marginBottom="5dp">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:selectableItemBackground">
    <ImageView
        android:id="@+id/contactpic"
        android:tag="image_tag"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="20dp"/>
    <TextView
        android:id="@+id/contactname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/contactpic"
        android:layout_marginLeft="40dp"
        android:text="Name"
        android:textAppearance="?android:attr/textAppearanceLarge"/>
    <TextView
        android:id="@+id/contacttype"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/contactname"
        android:layout_toRightOf="@+id/contactpic"
        android:layout_marginLeft="40dp"
        android:text="Type"
        android:textAppearance="?android:attr/textAppearanceMedium"/>
</RelativeLayout>

LogAdapter類。

public class LogAdapter extends RecyclerView.Adapter<ContactViewHolder> {

private List<ContactInfo> logList;

public LogAdapter(List<ContactInfo> logList) {
    this.logList = logList;
}

@Override
public int getItemCount() {
    return logList.size();
}

@Override
public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
    final String number;
    String name;
    ContactInfo ci = logList.get(i);
    name = ci.name;
    if (name.equals("-2")) {
        name = "Private";
    }
    contactViewHolder.vName.setText(name);
    contactViewHolder.vType.setText(ci.type);
    number = ci.number;
    }

    contactViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:" + number.trim()));
            if (ActivityCompat.checkSelfPermission(v.getContext(), Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
                v.getContext().startActivity(intent);
            }
        }
    });
}

@Override
public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View itemView = LayoutInflater.
            from(viewGroup.getContext()).
            inflate(R.layout.phone_calllog_card, viewGroup, false);

    return new ContactViewHolder(itemView);
}

}

phone_contact_card.xmlContactAdapter與之前的這些幾乎不同,但幾乎沒有變化。

<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
android:layout_marginBottom="5dp">
<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:selectableItemBackground">
    <ImageView
        android:id="@+id/contactpic"
        android:tag="image_tag"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="20dp"/>
    <TextView
        android:id="@+id/contactname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/contactpic"
        android:layout_marginLeft="40dp"
        android:layout_centerVertical="true"
        android:text="Name"
        android:textAppearance="?android:attr/textAppearanceLarge"/>
</RelativeLayout>

用於呼叫日志的適配器與聯系人巧合之間的區別在於,在進入片段時會顯示呼叫日志,並且會顯示來自呼叫日志的 10 個靜態結果。 但是對於接觸巧合,每次在serachview中輸入字母時,它必須具有某種動畫來刷新列表以查找巧合,因此這里有一些額外的方法。

public class ContactAdapter extends RecyclerView.Adapter<ContactViewHolder> {

private List<ContactInfo> contactList;

public ContactAdapter(List<ContactInfo> contactList) {
    this.contactList = contactList;
}

@Override
public int getItemCount() {
    return contactList.size();
}

@Override
public void onBindViewHolder(ContactViewHolder contactViewHolder, int i) {
    final String number;
    ContactInfo ci = contactList.get(i);
    contactViewHolder.vName.setText(ci.name);
    contactViewHolder.vPic.setImageResource(R.drawable.contact_icon_blue);
    number = ci.number;

    contactViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(Intent.ACTION_CALL);
            intent.setData(Uri.parse("tel:" + number.trim()));
            if (ActivityCompat.checkSelfPermission(v.getContext(), Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
                v.getContext().startActivity(intent);
            }
        }
    });
}

@Override
public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View itemView = LayoutInflater.
            from(viewGroup.getContext()).
            inflate(R.layout.phone_contact_card, viewGroup, false);

    return new ContactViewHolder(itemView);
}

public void animateTo(List<ContactInfo> contacts) {
    applyAndAnimateRemovals(contacts);
    applyAndAnimateAdditions(contacts);
    applyAndAnimateMovedItems(contacts);
}

private void applyAndAnimateRemovals(List<ContactInfo> newContacts) {
    for (int i = contactList.size() - 1; i >= 0; i--) {
        final ContactInfo model = contactList.get(i);
        if (!newContacts.contains(model)) {
            removeItem(i);
        }
    }
}

private void applyAndAnimateAdditions(List<ContactInfo> newContacts) {
    for (int i = 0, count = contactList.size(); i < count; i++) {
        final ContactInfo model = newContacts.get(i);
        if (!contactList.contains(model)) {
            addItem(i, model);
        }
    }
}

private void applyAndAnimateMovedItems(List<ContactInfo> newContacts) {
    for (int toPosition = newContacts.size() - 1; toPosition >= 0; toPosition--) {
        final ContactInfo model = newContacts.get(toPosition);
        final int fromPosition = contactList.indexOf(model);
        if (fromPosition >= 0 && fromPosition != toPosition) {
            moveItem(fromPosition, toPosition);
        }
    }
}

public ContactInfo removeItem(int position) {
    final ContactInfo model = contactList.remove(position);
    notifyItemRemoved(position);
    return model;
}

public void addItem(int position, ContactInfo model) {
    contactList.add(position, model);
    notifyItemInserted(position);
}

public void moveItem(int fromPosition, int toPosition) {
    final ContactInfo model = contactList.remove(fromPosition);
    contactList.add(toPosition, model);
    notifyItemMoved(fromPosition, toPosition);
}

3)實現邏輯

最后,在PhoneFragment ,這是使所有這些工作的實現。

public class PhoneFragment extends Fragment implements SearchView.OnQueryTextListener {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.phone_layout, container, false);

    //query Searchview
    svContact.setOnQueryTextListener(this);

    //Recyclerview
    mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this.getActivity()));
    //Loads the calllog
    mLogAdapter = new LogAdapter(DisplayCallLog());
    mRecyclerView.setAdapter(mLogAdapter);

    //RecyclerView animation
    RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
    itemAnimator.setAddDuration(1000);
    itemAnimator.setRemoveDuration(1000);
    mRecyclerView.setItemAnimator(itemAnimator);

    return view;
}

注意:由於通話記錄顯示正確,我將避免在此處復制DisplayCallLog()方法,因為它太長。

當在搜索視圖中輸入文本時,我們定義了新的適配器來實現在回收視圖中顯示巧合的功能。

    @Override
public boolean onQueryTextChange(String query) {
    final List<ContactInfo> filteredModelList = filter(ContactsList(), query);
    mContactAdapter.animateTo(filteredModelList);
    mRecyclerView.scrollToPosition(0);
    return true;
}

private List<ContactInfo> filter(List<ContactInfo> contacts, String query) {
    query = query.toLowerCase();

    final List<ContactInfo> filteredModelList = new ArrayList<>();
    for (ContactInfo contact : contacts) {
        final String name = contact.getContactName().toLowerCase();
        final String number = contact.getContactNumber().toLowerCase();
        Log.i("FILTERED_QUERY", "name " + name + "/ number " + number);
        if (name.contains(query) || number.contains(query)) {
            filteredModelList.add(contact);
        }
    }
    return filteredModelList;
}

    private ArrayList<ContactInfo> ContactsList() {

    ArrayList<ContactInfo> contactsList = new ArrayList<ContactInfo>();
    int contactID = 0;
    String contactNumber = null;
    String contactName = null;
    ContactInfo cI;
    int resultLimit = 0;

    Cursor cursorContacts = getActivity().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
            null, null, null, null);
    while (cursorContacts.moveToNext() && resultLimit<10) {
        contactID = cursorContacts.getInt(cursorContacts.getColumnIndexOrThrow(
                ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
        contactNumber = cursorContacts.getString(cursorContacts.getColumnIndexOrThrow(
                ContactsContract.CommonDataKinds.Phone.NUMBER));
        contactName = cursorContacts.getString(cursorContacts.getColumnIndexOrThrow(
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));

        cI = new ContactInfo();
        cI.id = contactID;
        cI.name = contactName;
        cI.number = contactNumber;
        Log.i("CONTACT_INFO", cI.toString());
        resultLimit++;
    }
    cursorContacts.close();
    return contactsList;
}

編輯 3 -> 新信息

我試過在啟動時只顯示聯系人。 因此,我應該看到一個聯系人列表,而不是可視化日志。 所以在片段的 onCreateView 我只是這樣做:

mContactAdapter = new ContactAdapter(ContactsList());
mRecyclerView.setAdapter(mContactAdapter);

而不是我之前在做什么:

mLogAdapter = new LogAdapter(DisplayCallLog());
mRecyclerView.setAdapter(mLogAdapter);

這樣,我只使用一個適配器,如果這是問題,它應該可以工作。 但不工作。 因此,問題必須與我實現聯系人的方式有關(我說的是從聯系人列表中獲取聯系人的原始列表,而不對其進行過濾),或者是 ContactAdapter 中的某些問題。 但是這個適配器和 LogAdapter 幾乎相同,所以我不知道......

我想我明白了。 這是因為您使用了多個適配器,用於顯示日志和調用數據的示例。 所以首先,你需要做的是,它只使用單個適配器和不同的項目類型視圖。 RecyclerView 具有針對不同 ViewHolder 的實現。

首先,嘗試使用上面的示例,僅使用單個適配器和不同的項目類型。 如果問題仍然存在,我稍后會提供示例,使用您上面的資源。

更新!

所以,我希望您正確理解,使用多個適配器可能會在下次更新視圖時產生問題(事件這不是您問題的關鍵,因為 RecyclerView 緩存了 ViewHolders)。 並且無需在您的示例中使用多個改編。 另一件事,我不理解上面代碼的所有作品。 更多信息需要調試你的所有項目...

但我也更新了 Searchable Samples(上面鏈接)的工作,以使用幾個 Item ViewHolder Types 和不同的搜索示例,下面是結果。 無論如何,這是比使用多個適配器更好的解決方案。 我也稍后在 Github 中共享代碼。

更新 GITHUB 鏈接!

在此處輸入圖片說明 在此處輸入圖片說明

試試這個:

public boolean onQueryTextChange(String query) {
    mContactAdapter = new ContactAdapter(ContactsList());
    mRecyclerView.setAdapter(mContactAdapter);
    //final List<ContactInfo> filteredModelList = filter(ContactsList(), query);
    //mContactAdapter.animateTo(filteredModelList);
    //mRecyclerView.scrollToPosition(0);
    return true;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM