【问题标题】:RecyclerView onClick stops working when using a navigation drawer (no fragments) [duplicate]RecyclerView onClick 使用导航抽屉时停止工作(无片段)[重复]
【发布时间】: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 下方。 &lt;DrawerLayout&gt; 应该是根,其他不是抽屉的东西——在这种情况下是&lt;NavigationView&gt;——应该在上面列出的ViewGroup 中;例如,以某种方式排列在 app_bar_navigation 布局内
  • @MikeM。感谢您将我链接到副本。遵循您的建议,使用DrawerLayout 作为根,并在这里和那里进行一些更改,问题得到解决。谢谢。

标签: java android android-recyclerview onclick listener


【解决方案1】:

您好 ping 实际上我不知道您的代码到底出了什么问题,但您可以查看我的代码,我做了同样的事情,它工作正常
这是包含导航抽屉的基本活动

public class BaseActivity extends AppCompatActivity implements
        NavigationView.OnNavigationItemSelectedListener {

    private NavigationView navigationView;
    private DrawerLayout fullLayout;
    private Toolbar toolbar;
    private ActionBarDrawerToggle drawerToggle;
    private int selectedNavItemId;
    List<User> userInfoList = new ArrayList<>();
    private TextView headerText;
    private TextView pointsTextView;
    private TextView groupTextView;
    String access;
    String client;
    String expiry;
    String uid;
    String type;
    String url;
    ArrayList<String> categories;
    View parentVeiw;
    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);

    }
    boolean doubleBackToExitPressedOnce = false;

    @Override
    public void onBackPressed() {
        parentVeiw=findViewById(R.id.activity_container);
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Snackbar.make(parentVeiw,"الرجاء اضغط مرة أخرى للخروج من البرنامج",Snackbar.LENGTH_SHORT).show();

        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                doubleBackToExitPressedOnce = false;
            }
        }, 2000);
    }

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        access = ((GlobalVAriables) this.getApplication()).getAccessToken();
        client = ((GlobalVAriables) this.getApplication()).getClient();
        expiry = ((GlobalVAriables) this.getApplication()).getExpiry();
        uid = ((GlobalVAriables) this.getApplication()).getUid();
        type = ((GlobalVAriables) this.getApplication()).getType();
        url = ((GlobalVAriables) this.getApplication()).getUrl();
        getCategories(url, access, type, client, expiry, uid);
        sendJsonRequestgetUserInfo(url, access, type, client, expiry, uid);



        /**
         * This is going to be our actual root layout.
         */
        fullLayout = (DrawerLayout) getLayoutInflater().inflate(R.layout.activity_base, null);
        /**
         * {@link FrameLayout} to inflate the child's view. We could also use a {@link android.view.ViewStub}
         */
        FrameLayout activityContainer = (FrameLayout) fullLayout.findViewById(R.id.activity_content);
        getLayoutInflater().inflate(layoutResID, activityContainer, true);

        /**
         * Note that we don't pass the child's layoutId to the parent,
         * instead we pass it our inflated layout.
         */
        super.setContentView(fullLayout);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        navigationView = (NavigationView) findViewById(R.id.navigationView); //        int currentapiVersion = android.os.Build.VERSION.SDK_INT; //        if (currentapiVersion == Build.VERSION_CODES.KITKAT){ //            toolbar.setPadding(0, getStatusBarHeight(), 0, 0);  } //

        if (useToolbar())
        {
            setSupportActionBar(toolbar);
        }
        else
        {
            toolbar.setVisibility(View.GONE);
        }

        setUpNavView();
    }

    /**
     * Helper method that can be used by child classes to
     * specify that they don't want a {@link Toolbar}
     * @return true
     */
    protected boolean useToolbar()
    {
        return true;
    }

    protected void setUpNavView()
    {
        navigationView.setNavigationItemSelectedListener(this);

        if( useDrawerToggle()) { // use the hamburger menu
            drawerToggle = new ActionBarDrawerToggle(this, fullLayout, toolbar,
                    R.string.drawer_open,
                    R.string.drawer_close);

            fullLayout.setDrawerListener(drawerToggle);
            drawerToggle.syncState();
        } else if(useToolbar() && getSupportActionBar() != null) {
            // Use home/back button instead
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setHomeAsUpIndicator(getResources()
                    .getDrawable(R.drawable.abc_ic_ab_back_mtrl_am_alpha));
        }
    }

    /**
     * Helper method to allow child classes to opt-out of having the
     * hamburger menu.
     * @return
     */
    protected boolean useDrawerToggle()
    {
        return true;
    }


    @Override
    public boolean onNavigationItemSelected(MenuItem menuItem) {
        fullLayout.closeDrawer(GravityCompat.START);
        selectedNavItemId = menuItem.getItemId();

        return onOptionsItemSelected(menuItem);
    }


    @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
        switch (id)
        {
            case R.id.main:
                Intent mainac = new Intent(this, MainActivity.class);
                startActivity(mainac);
                finish();


                break;

            case R.id.Categories:
                Intent Categories=new Intent(this,CategoryActivity.class);
                Categories.putExtra("categories", categories);
                startActivity(Categories);
                finish();
                break;
            case R.id.notifications:
                Intent notificationIntent=new Intent(this,NotificationsActivity.class);
                startActivity(notificationIntent);
                finish();

                break;
            case R.id.change_password:
                Intent changePassIntent=new Intent(this,changePassword.class);
                startActivity(changePassIntent);
                finish();

                break;
            case R.id.log_out:



                SharedPreferences sharedPrefs = getSharedPreferences(SignInActivity.PREFS_NAME, MODE_PRIVATE);
                SharedPreferences.Editor editor = sharedPrefs.edit();
                editor.clear();
                editor.commit(); //                user = "";
                //show login form
                Intent intent = new Intent(this, First_Activity.class);
                startActivity(intent);
                finish();

                break;
            case R.id.about_them:
                Intent aboutThemIntent=new Intent(this,AboutThem.class);
                startActivity(aboutThemIntent);
                finish();

                break;
            case R.id.about_us:
                Intent aboutUsIntent=new Intent(this,AboutUs.class);
                startActivity(aboutUsIntent);
                finish();

                break;




            default:
        }

        return super.onOptionsItemSelected(item);
    }}

这是扩展基础活动的活动

public class MainActivity extends BaseActivity {
    public static final int detail_id = 1;

    private bookListAdapter booklistadapter;

    List<book> aksarEste3araList = new ArrayList<>();

    RecyclerView aksarEste3araRecyclerView;

    List<book> sanfMofadalList = new ArrayList<>();
    RecyclerView sanfMofadalRecyclerView;

    String user;
    String access;
    String client;
    String expiry;
    String uid;
    String type;
    String url;
    TextView mostEste3aeaNmae, sanfMofadalName;
    ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mostEste3aeaNmae = (TextView) findViewById(R.id.most_este3ara_name);
        sanfMofadalName = (TextView) findViewById(R.id.sanf_mofadal_name);
        Typeface custom_font = Typeface.createFromAsset(getAssets(), "fonts/GE_SS_Three_Light_0.otf");

        mostEste3aeaNmae.setTypeface(custom_font);
        sanfMofadalName.setTypeface(custom_font);


        access = ((GlobalVAriables) this.getApplication()).getAccessToken();
        client = ((GlobalVAriables) this.getApplication()).getClient();
        expiry = ((GlobalVAriables) this.getApplication()).getExpiry();
        uid = ((GlobalVAriables) this.getApplication()).getUid();
        type = ((GlobalVAriables) this.getApplication()).getType();
        url = ((GlobalVAriables) this.getApplication()).getUrl();


//Toast.makeText(getBaseContext(),access,Toast.LENGTH_SHORT).show();


        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(refreshedToken);


        //        aksar este3ara
        aksarEste3araRecyclerView = (RecyclerView) findViewById(R.id.aksar_este3ara_recycler_view);
        sendJsonRequestAksarEste3ara(url, access, type, client, expiry, uid);
        aksarEste3araRecyclerView.addOnItemTouchListener(new RecyclerTouchListener(getBaseContext(), aksarEste3araRecyclerView, new RecyclerTouchListener.ClickListener() {
            @Override
            public void onClick(View view, int position) {
                Intent i = new Intent(getBaseContext(), BookDetailsActivity.class);
                i.putExtra("goo", aksarEste3araList.get(position).getCategoryId());
                i.putExtra("bookId", aksarEste3araList.get(position).getBookId());
                startActivityForResult(i, detail_id);

            }

            @Override
            public void onLongClick(View view, int position) {
                Intent i = new Intent(getBaseContext(), BookDetailsActivity.class);
                i.putExtra("goo", aksarEste3araList.get(position).getCategoryId());
                i.putExtra("bookId", aksarEste3araList.get(position).getBookId());
                startActivityForResult(i, detail_id);

            }
        }));


        //        sanf mofadal
        sanfMofadalRecyclerView = (RecyclerView) findViewById(R.id.sanf_mofadal_recycler_view);

        sendJsonRequestSanfMofadal(url, access, type, client, expiry, uid);

        sanfMofadalRecyclerView.addOnItemTouchListener(new RecyclerTouchListener(getBaseContext(), sanfMofadalRecyclerView, new RecyclerTouchListener.ClickListener() {
            @Override
            public void onClick(View view, int position) {
                Intent i = new Intent(getBaseContext(), BookDetailsActivity.class);
                i.putExtra("goo", sanfMofadalList.get(position).getCategoryId());
                i.putExtra("bookId", sanfMofadalList.get(position).getBookId());
                startActivityForResult(i, detail_id);

            }

            @Override
            public void onLongClick(View view, int position) {
                Intent i = new Intent(getBaseContext(), BookDetailsActivity.class);
                i.putExtra("goo", sanfMofadalList.get(position).getCategoryId());
                i.putExtra("bookId", sanfMofadalList.get(position).getBookId());
                startActivityForResult(i, detail_id);

            }
        }));

    }

如果您需要任何澄清,请随时询问

【讨论】:

  • 感谢详细解答;但是,我想了解我的方法出了什么问题..
  • 没问题希望能多多帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
  • 2018-01-16
相关资源
最近更新 更多