【发布时间】:2018-08-12 12:57:10
【问题描述】:
我遇到了this 帖子,其中讨论了如何在不使用片段的情况下创建导航抽屉。撇开我不想使用片段的动机不谈,我现在面临一个问题,即我的RecyclerView 项目的 onClick 事件不再被触发。
TL;DR:如果我从布局 xml 中删除 DrawerLayout 部分,onClick 事件将按预期触发。在我的活动布局 xml 中定义 DrawerLayout 似乎会导致 RecyclerView 的所有事件(例如滚动/单击)停止工作。我的另一个观察结果是包含DrawerLaout 会导致我的RecyclerView 的第一个元素根本不显示。我无法弄清楚是什么导致 onClick 事件被阻止。
以下是我的代码的相关部分:
1. NavigationActivity 将被其他希望显示 Navigation Drawer 的 Activity 扩展
public class NavigationActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
protected void onCreateDrawer() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.navigation, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_todays_goals) {
} else if (id == R.id.nav_freetime) {
Intent intent = new Intent(this,FreeTimeActivity.class);
startActivity(intent);
} else if (id == R.id.nav_goaltime) {
Intent intent = new Intent(this,GoalTimeActivity.class);
startActivity(intent);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
@Override
public void setContentView(@LayoutRes int layoutResID)
{
super.setContentView(layoutResID);
onCreateDrawer();
}
}
2。使用有问题的 RecyclerView 扩展 NavigationActivity 的活动之一(仅显示相关代码):
public class FreeTimeActivity extends NavigationActivity implements FreeTimeAdapter.FreeTimeAdapterOnClickHandler, LoaderManager.LoaderCallbacks<Cursor> {
private RecyclerView mRecyclerView;
private ProgressBar mLoadingIndicator;
private FreeTimeAdapter mFreeTimeAdapter;
private int mPosition = RecyclerView.NO_POSITION;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_freetime);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview_seasons);
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
mFreeTimeAdapter = new FreeTimeAdapter(this, this);
LinearLayoutManager layoutManager =
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(mFreeTimeAdapter);
showLoading();
getSupportLoaderManager().initLoader(FREETIME_LOADER_ID, null, this);
}
@Override
public void onClickFreeTimeListItem(String name) {
Intent intent = new Intent(this, FreeTimeDetailsActivity.class);
//TODO uri should be set as freetime_goals rather than goals.
Uri uri = LifeTimeContract.FreeTimeGoalEntry.CONTENT_URI;
uri = uri.buildUpon().appendPath(name).build();
intent.setData(uri);
intent.putExtra("freezone_name",name);
startActivity(intent);
}
}
onClickFreeTimeListItem 方法是在单击mRecyclerView 实例中的项目时应调用的方法。我尝试调试 RecyclerView 使用的FreeTimeAdapter 类,它似乎按预期注册了侦听器,但是稍后单击RecyclerView 中的项目时永远不会调用onClick 方法。以下是FreeTimeAdapter 类的代码:
public class FreeTimeAdapter extends RecyclerView.Adapter<FreeTimeAdapter.FreeTimeAdapterViewHolder> {
private final Context mContext;
final private FreeTimeAdapterOnClickHandler mClickHandler;
/**
* The interface that receives onClickFreeTimeListItem messages.
*/
public interface FreeTimeAdapterOnClickHandler {
void onClickFreeTimeListItem(String name);
}
private Cursor mCursor;
/**
* Creates a ForecastAdapter.
*
* @param context Used to talk to the UI and app resources
* @param clickHandler The on-click handler for this adapter. This single handler is called
* when an item is clicked.
*/
public FreeTimeAdapter(@NonNull Context context, FreeTimeAdapterOnClickHandler clickHandler) {
mContext = context;
mClickHandler = clickHandler;
}
@Override
public FreeTimeAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
int layoutId = R.layout.freetime_list_items;
View view = LayoutInflater.from(mContext).inflate(layoutId, viewGroup, false);
view.setFocusable(true);
return new FreeTimeAdapterViewHolder(view);
}
@Override
public void onBindViewHolder(FreeTimeAdapterViewHolder freeTimeAdapterViewHolder, int position) {
mCursor.moveToPosition(position);
String freeTimeName = mCursor.getString(FreeTimeActivity.INDEX_FREETIME_NAME);
int id = mCursor.getInt(FreeTimeActivity.INDEX_FREETIME_ID);
String startTime = mCursor.getString(FreeTimeActivity.INDEX_FREETIME_START_TIME);
String endTime = mCursor.getString(FreeTimeActivity.INDEX_FREETIME_END_TIME);
String endDate = mCursor.getString(FreeTimeActivity.INDEX_FREETIME_END_DATE);
freeTimeAdapterViewHolder.tvFreeTimeName.setText(freeTimeName);
freeTimeAdapterViewHolder.tvStartTime.setText(startTime);
freeTimeAdapterViewHolder.tvEndTime.setText(endTime);
freeTimeAdapterViewHolder.tvEndDate.setText(endDate);
/*FreeTimeItemDataHolder freeTimeItemDataHolder = new FreeTimeItemDataHolder(id,freeTimeName);*/
freeTimeAdapterViewHolder.itemView.setTag(R.string.tag_freetime_id,id);
freeTimeAdapterViewHolder.itemView.setTag(R.string.tag_freetime_name,freeTimeName);
}
@Override
public int getItemCount() {
if (null == mCursor) return 0;
return mCursor.getCount();
}
void swapCursor(Cursor newCursor) {
mCursor = newCursor;
notifyDataSetChanged();
}
class FreeTimeAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final TextView tvFreeTimeName;
final TextView tvStartTime;
final TextView tvEndTime;
final TextView tvEndDate;
FreeTimeAdapterViewHolder(View view) {
super(view);
//TODO add additional views to each item in the recyclerview such as delete button etc
tvFreeTimeName = (TextView) view.findViewById(R.id.tv_freetime_name);
tvStartTime = (TextView) view.findViewById(R.id.tv_freetime_start_time);
tvEndTime = (TextView) view.findViewById(R.id.tv_freetime_end_time);
tvEndDate = (TextView) view.findViewById(R.id.tv_freetime_end_date);
view.setOnClickListener(this);
}
/**
* This gets called by the child views during a click. We fetch the date that has been
* selected, and then call the onClickFreeTimeListItem handler registered with this adapter
*
* @param v the View that was clicked
*/
@Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
mCursor.moveToPosition(adapterPosition);
String name = mCursor.getString(FreeTimeActivity.INDEX_FREETIME_NAME);
mClickHandler.onClickFreeTimeListItem(name);
}
}
}
包含回收站视图的活动的布局 xml 文件
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/pb_loading_indicator"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center"
android:visibility="invisible" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview_seasons"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="8dp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:src="@drawable/ic_add_box_black_24dp"
android:layout_margin="48dp"
android:onClick="onClickAddFreeTime"/>
<!-- Temporariliy added to navigate to goal time screen. Remove this when app navigation bar is coded -->
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_all_goals"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|bottom"
android:src="@drawable/ic_add_box_black_24dp"
android:layout_margin="48dp"
android:onClick="onClickAllGoals"/>
<android.support.v4.widget.DrawerLayout 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"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_navigation"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_navigation"
app:menu="@menu/activity_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
</FrameLayout>
在我介绍NavigationActivity 和相关的抽屉式导航代码之前,相同的代码库运行良好。
【问题讨论】:
-
点击时有视觉反馈吗?你能滚动
RecyclerView吗?您确定在 XML 中正确设置了DrawerLayout吗? -
@MikeM。你说的对。即使有 100 多个项目,我也无法滚动 RecyclerView。您怀疑是什么原因造成的?我用更多信息编辑了帖子。任何方向都会很有帮助。
-
是的,布局有点古怪。您不想将
DrawerLayout“分层”到其他所有内容上。它应该包含两件事:抽屉打开的所有主要内容,以及抽屉本身。您的主要内容被拆分,其中一部分(包括RecyclerView)最终位于DrawerLayout下方。<DrawerLayout>应该是根,其他不是抽屉的东西——在这种情况下是<NavigationView>——应该在上面列出的ViewGroup中;例如,以某种方式排列在app_bar_navigation布局内 -
@MikeM。感谢您将我链接到副本。遵循您的建议,使用
DrawerLayout作为根,并在这里和那里进行一些更改,问题得到解决。谢谢。
标签: java android android-recyclerview onclick listener