使用新适配器

时间:2016-07-01 09:50:35

标签: android android-recyclerview

我有一个顶部有一个Searchview的片段,在下面我显示了一个带有las 10个电话的通话记录。要显示通话记录,我使用recyclerview和卡片。这种行为很好,但现在我想实现其他的东西。

如果我在Searchview中搜索一个名字,我想做一些事情,例如结果列表更新时显示与联系人列表的巧合。这是,我需要重复使用recyclerview,但此时,我将显示与联系人列表的巧合,而不是通话记录。

我已使用找到的代码here,但无效。我正在做一些测试,看看有什么问题,而且我发现我无法重复使用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 - &gt;评论

我尝试在启动时加载联系人列表而不是日志列表,但它也没有加载它。也许问题是联系人列表要长吗?

编辑2 - &gt;广泛的代码添加

1)设置SearchView

我没有在操作栏中添加搜索视图,而是使用cardview来包含它。这是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。对于展位使用calllog和接触巧合,这是相同的。

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

现在,每种用途的不同之处在于布局和适配器。从calllog开始,这里是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()方法太长。

当在searchview中输入文本时,我们定义新的适配器以实现在recyclerview中显示巧合的功能。

    @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 - &gt;新信息

我尝试在启动时只显示联系人。因此,我应该看到一个联系人列表,而不是可视化日志。所以在片段的onCreateView中,我只是这样做:

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

而不是我以前做过的事情:

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

这样,我只使用一个适配器,如果这是问题,它应该可以工作。但是没有用。因此,问题必须与我实现联系的方式有关(我在谈论从联系人列表中获取联系人的原始列表,而不过滤它们),或者在ContactAdapter中出现错误。但是这个适配器和LogAdapter几乎完全相同,所以我不知道......

2 个答案:

答案 0 :(得分:1)

我想我遇到了问题。这是因为你使用了几个适配器,用于显示日志和呼叫数据的示例。首先,您需要做什么,它只使用单个适配器和项目类型的不同视图。 RecyclerView实现了不同的ViewHolder - look at this example

首先,尝试使用上面的示例,仅使用单个适配器和不同的项类型。如果问题仍然存在,我将在稍后使用上面的资源提供示例。

<强>更新<!/强>

所以,我希望您能够正确理解,使用多个适配器可能会在下次更新视图时出现问题(事件这不是您问题的关键,因为RecyclerView会缓存ViewHolders)。并且您的示例中不需要使用多个适应器。另一件事,我不理解上面的所有代码作品。有关更多信息需要调试所有项目...

但我还更新了可搜索样本(上面链接)的工作,以使用项目ViewHolder类型的几个示例和搜索中的不同,下面是结果。无论如何,它比使用多个适配器更好的解决方案。我也在Github Later中共享代码。

UPDATE GITHUB LINKS!

enter image description here enter image description here

答案 1 :(得分:0)

试试这个:

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