ViewPager 中的 Fragment 按钮在错误引用时触发 onClickListener

Posted

技术标签:

【中文标题】ViewPager 中的 Fragment 按钮在错误引用时触发 onClickListener【英文标题】:Button of a Fragment inside ViewPager trigger onClickListener on wrong reference 【发布时间】:2017-02-19 18:08:48 【问题描述】:

对不起我的愚蠢标题,我会在下面清楚地描述它:

情况

我有一个 ViewPager,里面有 4 个 OnBoardingFragments。每个Fragment 具有完全相同的布局,即来自同一xml 文件的inflated。这个布局包含一个Button,我称之为btnNext,我为它设置了OnClickListener

我的 PagerAdapter 的函数 getItem

@Override
public Fragment getItem(int position) 
    String title, description, button;
    int resource;
    boolean end = false;
    switch (position) 
        case 0:
            title = context.getString(R.string.on_boarding_title_1);
            description = context.getString(R.string.on_boarding_description_1);
            resource = R.drawable.on_boarding_bg_0;
            button = context.getString(R.string.on_boarding_button_1);
            break;
        case 1:
            title = context.getString(R.string.on_boarding_title_2);
            description = context.getString(R.string.on_boarding_description_2);
            resource = R.drawable.on_boarding_bg_1;
            button = context.getString(R.string.on_boarding_button_2);
            break;
        case 2:
            title = context.getString(R.string.on_boarding_title_3);
            description = context.getString(R.string.on_boarding_description_3);
            resource = R.drawable.on_boarding_bg_2;
            button = context.getString(R.string.on_boarding_button_3);
            break;
        default:
            title = context.getString(R.string.on_boarding_title_4);
            description = context.getString(R.string.on_boarding_description_4);
            resource = R.drawable.on_boarding_bg_3;
            button = context.getString(R.string.on_boarding_button_4);
            end = true;
    
    return OnBoardingFragment.newInstance(title, description, resource, button, end);


@Override
public int getCount() 
    return 4;

OnBoardingFragment的功能:

public static OnBoardingFragment newInstance(String title, String description, int resource,
                                             String button, boolean end) 
    Bundle bundle = new Bundle();
    bundle.putString(EXTRA_TITLE, title);
    bundle.putString(EXTRA_DESCRIPTION, description);
    bundle.putInt(EXTRA_IMAGE, resource);
    bundle.putString(EXTRA_BUTTON, button);
    bundle.putBoolean(EXTRA_END, end);
    OnBoardingFragment fragment = new OnBoardingFragment();
    fragment.setArguments(bundle);
    return fragment;


@Override
public void onCreate(@Nullable Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    Bundle bundle = getArguments();
    if (bundle != null) 
        title = bundle.getString(EXTRA_TITLE);
        description = bundle.getString(EXTRA_DESCRIPTION);
        button = bundle.getString(EXTRA_BUTTON);
        end = bundle.getBoolean(EXTRA_END);
        imageResource = bundle.getInt(EXTRA_IMAGE);
        show log ---> Log.e(this.toString() + "/" + end + "/" + title);
    


@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
    View rootView = inflater.inflate(R.layout.on_boarding_fragment, container, false);
    TextView tvTitle = (TextView) rootView.findViewById(R.id.tv_title);
    TextView tvDescription = (TextView) rootView.findViewById(R.id.tv_description);
    TextView btnDiscovery = (TextView) rootView.findViewById(R.id.tv_discovery);
    imageView = (ImageView) rootView.findViewById(R.id.iv_image);
    final Button btnNext = (Button) rootView.findViewById(R.id.btn_next);
    if (end) 
        btnDiscovery.setVisibility(View.VISIBLE);
        btnDiscovery.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                startRegionActivity();
            
        );
    
    btnNext.setText(button);
    btnNext.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            show log ---> Log.e(OnBoardingFragment.this.toString() + "/" + end + "/" + title + "/" + ((Button)v).getText());
            if (end) 
                ((SplashActivity) getActivity()).gotoNextPage();
             else 
                startLoginActivity();
            
        
    );
    tvTitle.setText(title);
    tvDescription.setText(description);
    ImageUtils.loadBitmap(getActivity(), imageResource, imageView, 0.8f, new ImageUtils.LoadBitmapCallback() 
        @Override
        public void onLoadComplete(ImageView imageView) 

        

        @Override
        public void onLoadFail() 

        
    );

    return rootView;

问题是

当我的应用启动时它显示first Fragment,然后我按下Button并触发onItemClick()方法,该方法被引用到last Fragment.

创建Fragment时记录

OnBoardingFragmenta8ede47 id=0x7f10013b/false/XIN CHÀO!
OnBoardingFragment8787674 #0 id=0x7f10013b/false/BÁN LIỀN TAY, KIẾM TIỀN NGAY
OnBoardingFragment119f79d #1 id=0x7f10013b/false/CHAT MIỄN PHÍ
OnBoardingFragment1ee7412 #2 id=0x7f10013b/true/NGƯỜI THẬT, HÀNG THẬT

onClickListener() 被触发时的日志

OnBoardingFragment1ee7412 #2 id=0x7f10013b/true/NGƯỜI THẬT, HÀNG THẬT/Đi chợ ngay nào!

btnNext 初始化时的日志:

button: android.support.v7.widget.AppCompatButton17c69e97 VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next
button: android.support.v7.widget.AppCompatButton31941c VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next
button: android.support.v7.widget.AppCompatButton30765b87 VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next
button: android.support.v7.widget.AppCompatButton9cf19e VFED..C. ......I. 0,0-0,0 #7f1002c8 app:id/btn_next

问题

为什么会发生以及如何解决?

【问题讨论】:

我猜你的开关是问题所在,记录收到的值,因为你使用default 作为最后一个元素,int position 可能不是预期的。您是否为适配器实现了 getCount() 方法? @AxelH 是的,我覆盖了 getCount() 方法并且简单返回 4。 @AxelH 我认为 switch 语句很好。所有片段均已正确初始化。 看this的回答。只需保存当前可见的片段(例如,作为静态变量)。因此,当您点击按钮时,您始终能够获得当前看到的片段。 发布更多代码。您分享的内容无法帮助您 【参考方案1】:

请参考以下链接中的示例以使用具有多个片段的视图寻呼机:https://guides.codepath.com/android/ViewPager-with-FragmentPagerAdapter

【讨论】:

这不是我的问题的答案。【参考方案2】:

当用户单击按钮时,将该事件发送回活动(或您有 viewpager 引用的地方)。从那里,您应该检查 viewpager 中的哪些片段是可见的(参见 Determine when a ViewPager changes pages 和 How to determine when Fragment becomes visible in ViewPager),然后您就会知道如何处理该事件。

【讨论】:

【参考方案3】:

您可以使用侦听器接口获取片段并创建获取位置的方法并将其发送到您声明 viewpager 的位置 1.首先在那个片段中创建那个接口的匿名对象 2. 其次将该对象传递给 PagerAdapter 3. 第三,您可以在 PagerAdapter 中使用该对象,并使用片段位置调用接口中使用的方法 4. 您可以在该接口的匿名内部类中的方法上包含片段布局处理代码

请试试这个,它会起作用的。希望你能明白我所说的。

【讨论】:

使用监听器是我解决问题的一种方式。但我的问题是“为什么会发生”,你能解释一下吗? 是因为boolean值return true并转到默认值,所以省略默认值,加一个case值到3包含默认的代码。并在案例 3 中设置标志值 true:,希望它会起作用,试试吧 mr.icetea , 请把break默认【参考方案4】:

case 3: 末尾和default 中使用case 3:,只需添加一个break 即可。

【讨论】:

【参考方案5】:

在默认块中添加 break 语句,并在 case 0,1,2 中传递参数 end = false

【讨论】:

以上是关于ViewPager 中的 Fragment 按钮在错误引用时触发 onClickListener的主要内容,如果未能解决你的问题,请参考以下文章

如何从使用 Fragment 的 ViewPager2 获得用户点击?

BottomNavigationView+ViewPager+Fragment 底部导航按钮 kotlin版本

BottomNavigationView+ViewPager+Fragment 底部导航按钮 kotlin版本

Android 底部按钮BottomNavigationView + Fragment + viewPager 的使用

更新 viewpager 内的 Fragment 视图而不重新加载数据

在 ViewPager 中刷新 Fragment 视图