防止Recyclerview拦截滚动/触摸事件

时间:2015-07-11 21:20:33

标签: android android-recyclerview

所以我到处寻找这个,我被困了几个小时;我真的需要帮助!

所以我在另一个scrollview中有一个(固定大小)的recyclerview,它是nestedscrollview。我在这个视图上也有CollapsingToolbarLayout。问题是,当我滚动整个视图并且我在Recyclerview上时,CollapsingToolbarLayout不会扩展/收缩(只有在CollapsingToolbarLayout签约时才会这样做,而且我向下滚动,所以它确实展开了)。否则,当我在recyclerview上时,CollapsingToolbarLayout永远不会对滚动更改做出反应。我试图拦截触摸并返回错误,但没有任何效果。

有什么建议吗?

更新

我尝试做的一个很好的例子是Whatsapp的个人资料活动,其中包含CollapsingToolbarLayout,如果个人资料是一个群组,则会显示该群组中的用户列表。这正是我在这里尝试做的,但是当我在该用户列表中滚动时,它不会滚动整个视图(recylcler视图正在拦截..)

1 个答案:

答案 0 :(得分:0)

public class ProgramRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

/** 
This is an abstract class that all of my viewholders inherit from. 
This is a contract telling me that any subclasses that inherit from this
base class are required to write their own `public void bind(int position,
Program program);` method. 
*/
abstract class ProgramBaseViewHolder extends RecyclerView.ViewHolder {

    public ProgramBaseViewHolder(View itemView) {
        super(itemView);
    }

    public abstract void bindDataToView(int position, Program program);
}

/**`@Bind` and Butterknife.bind is part of a viewbinding library called 
Butterknife. This usage of "bind" is the equivalent of your `findViewById()` 
calls. */

/**
This is the Airtime view that holds airtimes. It is a view holder that
inherits from my base view holder and implements its own version if bind.
*/
class AirtimeViewHolder extends ProgramBaseViewHolder {
    @Bind(R.id.program_airtimes)
    TextView mProgramAirtimes;

    static final int viewType = 0;

    public AirtimeViewHolder(View itemView) {
        super(itemView);
        /**This call to butterknife can be replaced with an
        itemView.findViewById(R.id.yourview) */
        ButterKnife.bind(this, itemView);
    }

    //This is where you set your text and hide or show your views.
    @Override
    public void bindDataToView(int position, Program program) {
        List<Airtime> airtimes = program.getAirtimes();
        if (!airtimes.isEmpty()) {
            mProgramAirtimes.setText(Utils.getFriendlyAirtimes(airtimes));
        } else {
            mProgramAirtimes.setText(
                    Utils.getFriendlyAirTime(program.getAirtime()));
        }
    }
}

/**
This is the Description view that holds descriptions. It is a view holder  
that inherits from my base view holder and implements its own version if    
bind.
*/
class DescriptionViewHolder extends ProgramBaseViewHolder {
    @Bind(R.id.description_card_layout)
    TextView mProgramDescription;

    static final int viewType = 1;

    public DescriptionViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    @Override
    public void bindDataToView(int position, Program program) {
        mProgramDescription.setText(Html.fromHtml(program.getFullDescription()));
    }
}
//This is another type of view with another different type of layout.
class HostsViewHolder extends ProgramBaseViewHolder {
    @Bind(R.id.card_view_host_name)
    TextView mProgramHostName;

    static final int viewType = 2;

    public HostsViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    @Override
    public void bindDataToView(int position, Program program) {
        mProgramHostName.setText(program.getHosts().get(position - 2).getDisplayName());
    }
}
//Again another type of view extending my base view.
class CategoriesViewHolder extends ProgramBaseViewHolder {
    @Bind(R.id.program_categories)
    TextView mProgramCategories;
    static final int viewType = 42;

    public CategoriesViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    @Override
    public void bindDataToView(int position, Program program) {
        List<Category> categoryList = program.getCategories();
        StringBuilder stringBuilder = new StringBuilder();
        for (Category category : categoryList) {
            stringBuilder.append(category.getTitle())
                    .append(" ");
        }
        mProgramCategories.setText(stringBuilder.toString());
    }
}

//This is where the normal looking recycler view code comes in.
private Context mContext;
private LayoutInflater mInflater;
private Program mProgramData;
private int mNextProgramId;

public ProgramRecyclerAdapter(Context context) {
    mContext = context;
    mInflater = LayoutInflater.from(mContext);
}

/**This method is where I am determining what view type each item in my list 
will be. I wanted a single airtimes view followed by a single description 
view and then X amount of hosts views and a single category view. I return 
position in the third else if because the position helps me determine which 
host name to display in the bindDataToViews call of the HostViewHolder.*/
@Override
public int getItemViewType(int position) {
    if (position == AirtimeViewHolder.viewType) {
        return AirtimeViewHolder.viewType;
    } else if (position == DescriptionViewHolder.viewType) {
        return DescriptionViewHolder.viewType;
    } else if (position > DescriptionViewHolder.viewType
            && position <= DescriptionViewHolder.viewType + getHostsNum()) {
        return position;
    } else {
        return CategoriesViewHolder.viewType;
    }
}

//This method figures out how many hosts will be displayed
private int getHostsNum() {
    if (mProgramData != null) {
        return mProgramData.getHosts().size();
    }
    return 0;
}
// This method determines if I will show a category view or not.
private int getCategoriesNum() {
    if (mProgramData != null && mProgramData.getCategories().size() > 0) {
        return 1;
    }
    return 0;
}

/**This returns haw many items will be in the list. 1 Airtime view, 1 
Description view, x amount of Host views and 0 or 1 category views */
@Override
public int getItemCount() {
    return 2 + getHostsNum() + getCategoriesNum();
}

/** This returns the appropriate View holder for the requested view type that 
was set by getItemViewType()which is determined by position. I pass the inflated parent view and the data.     
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == AirtimeViewHolder.viewType) {
        return new AirtimeViewHolder(mInflater.inflate(R.layout.airtime_card_layout, parent, false));
    } else if (viewType == DescriptionViewHolder.viewType) {
        return new DescriptionViewHolder(mInflater.inflate(R.layout.description_card_layout, parent, false));
    } else if (viewType > DescriptionViewHolder.viewType
            && viewType <= DescriptionViewHolder.viewType + getHostsNum()) {
        return new HostsViewHolder(mInflater.inflate(R.layout.hosts_card_layout, parent, false));
    } else
        return new CategoriesViewHolder(mInflater.inflate(R.layout.categories_card_layout, parent, false));
}

/*This method is what ties everything together. After I ensure that the data 
is not null I call bindDataToView on a ProgramBaseViewHolder. Depending on 
which type of subclass it is will determine which overridden bindData code to 
use and what view to display. */
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    ProgramBaseViewHolder baseViewHolder = (ProgramBaseViewHolder) holder;
    if (mProgramData != null) {
        baseViewHolder.bindDataToView(position, mProgramData);
    }
}

//This is used to set the data for this program
public void setProgramData(Program program) {
    mProgramData = program;
}

public Program getProgramData() {
    return mProgramData;
}

public boolean isEmpty() {
    return mProgramData == null;
}
}

这是Airtime布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin">  
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:orientation="vertical"> 
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/airtimes_label"
        android:textSize="18dp"
        android:textStyle="bold"
        android:textAppearance="@style/TextAppearance.AppCompat.Body2"
        android:layout_marginBottom="4dp"/> 
    <TextView
        android:id="@+id/program_airtimes"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textAppearance="@style/TextAppearance.AppCompat.Title" />  
</LinearLayout>

这是我的主机布局。您会注意到我没有在这里使用大多数视图,因为这是一个正在进行的应用程序,并且相同的布局用于包含主机图片及其程序的不同活动。

    <?xml version="1.0" encoding="utf-8"?>
<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/host_card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/card_margin"
    card_view:cardBackgroundColor="@color/white"
    card_view:cardCornerRadius="2dp">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp" />
        <ImageView
            android:id="@+id/host_image"
            android:layout_width="112dp"
            android:layout_height="112dp"
            android:layout_alignParentLeft="true"
            android:visibility="gone"
            android:layout_centerVertical="true"
            android:layout_marginRight="8dp" />
        <LinearLayout
            android:id="@+id/details"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_toRightOf="@id/host_image"
            android:orientation="vertical">
            <TextView
                android:id="@+id/card_view_host_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:layout_margin="16dp"
                android:textAppearance="@style/TextAppearance.AppCompat.Body2"
                android:layout_gravity="left" />
            <TextView
                android:id="@+id/card_view_hosts_programs"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="gone"
                android:textStyle="bold"
                android:textSize="12sp"
                android:layout_marginBottom="16dp"
                android:layout_gravity="left"/>
        </LinearLayout>
    </RelativeLayout>
</android.support.v7.widget.CardView>

以下是处理上述回收器适配器的活动的布局。

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout   
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/detail_backdrop_height"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:background="@color/white">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginEnd="64dp"
        app:expandedTitleMarginStart="48dp"
        app:expandedTitleTextAppearance="@style/ExpandedAppBar"
        app:collapsedTitleTextAppearance="@style/CollapsedAppBar"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            android:id="@+id/program_collapsing_image_view"
            android:layout_width="match_parent"
            android:layout_height="256dp"
            android:src="@drawable/kzfr_logo"
            android:scaleType="centerCrop"
            app:layout_collapseMode="parallax" />

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_collapseMode="pin" />

    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

<android.support.v7.widget.RecyclerView
    android:id="@+id/host_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

我的持卡人在顶部和底部都有边距所以如果您使用卡片视图上的边距我确信您可以完成与WhatsApp相同类型的视图,它看起来像是同一张卡片。它真的有多个卡片视图,有0个顶部和底部边距。在whatsApp视图中,您在谈论它显示组的参与者的位置参与者,添加参与者甚至ExitGroup按钮视图都是同一回收者视图的一部分。我怀疑它是嵌套滚动视图中的回收器视图,它们不是一起工作的。

This is the view that is produced with some data. The Categories view is cut off but it is there.