OnTouchListener / OnClickListener无法在Fragment的布局中工作

时间:2014-08-08 08:43:40

标签: android android-layout android-fragments

请记住,我是Android的初学者,所以有可能在某个地方我忽略了一些东西。此外,我还有一个问题,因为我对整个项目的态度可能是错误的。

我有一个通过DrawerLayout实现侧边菜单的应用程序。 “主屏幕”是一个片段和抽屉我创建了侧面菜单,其中包含一个列表。之后,这就是我点击侧边菜单时更改碎片的方式:

private void displayView(int position) {
    // update the main content by replacing fragments

    Fragment fragment = null;
    switch (position) {
        case 0:
            fragment = new HomeFragment();
            break;
        case 1:
            fragment = new FavoritesFragment();
            break;
        case 2:
            fragment = new LastVisitedFragment();
            break;
        case 3:
            fragment = new SettingsFragment();
            break;
        default:
            break;
    }

    if (fragment != null) {
        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();

        // update selected item and title, then close the drawer
        mDrawerList.setItemChecked(position, true);
        mDrawerList.setSelection(position);
        setTitle(navMenuTitles[position]);
        mDrawerLayout.closeDrawer(mDrawerList);
    } else {
        Log.e("MainActivity", "Error in creating fragment");
    }
}

上面的代码在我的主要活动中实现。接下来是我的HomeFragment的外观: (主页片段是我的主页,所以说)

public class HomeFragment extends Fragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        Log.i("HomeFragment", "OK");
        View rootView = inflater.inflate(R.layout.fragment_home, container, false);
        rootView.setOnClickListener(new View.OnClickListener() {

            @
            Override
            public void onClick(View v) {
                Log.i("HomeFragment", "OK0");
                switch (v.getId()) {
                    case R.id.rec_prod1:
                        Log.i("HomeFragment", "OK1");
                        Intent intent1 = new Intent(getActivity(), SingleItemActivity.class);
                        startActivity(intent1);
                        break;
                    case R.id.rec_prod2:
                        Log.i("HomeFragment", "OK2");
                        Intent intent2 = new Intent(getActivity(), SingleItemActivity.class);
                        startActivity(intent2);
                        break;
                    case R.id.rec_prod3:
                        Log.i("HomeFragment", "OK3");
                        Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
                        startActivity(intent3);
                        break;

                }
            }
        });


        return rootView;
    }

}

我已经尝试使用onTouchListener,但也没有用,唯一的区别是onTouch它进入了onTouch方法,打赌后没有发生任何事情。在这个网站的某个地方,我有红色设置scrollview clickable = true和所有childs为false,以便它可以工作,但这也没有。 fragment_home.xml也是一个自定义布局,其中Parent是一个ScrollView(它是一个包含三个颜色和5行但每个元素不同的列表,它们都有一个Imageview和不同数量的textview,我没有使用ListView或GridList因为每一行都有一个标题,每行中的元素都有不同的布局)我只附加了它的概述,因为真正的xml代码超过800行。

<ScrollView>
<LinearLayout>
   <!--This part repeats 5 times creating each row -->  
   <TextView>   
   <LinearLayout>
     <!-- This part repeats 3 times for each element of a column -->
     <RelativeLayout>
        <ImageView>
            <!-- This part changes acodringly to the number of textviews, I can have 1 to 3 TextViews here-->
            <LinearLayout>
              <TextView>
              <TexytView>
            </LinearLayout>
    </RelativeLayout>
  </LinearLayout>           
</LinearLayout>
</ScrollView> 

所以我有两个主要问题。 1.为什么点击/触摸不起作用。 2.项目结构(架构)是否正常?整个想法是,当点击发生时,一些元素将我带到产品视图屏幕,而其他元素带到产品元素列表(填充所有这些的数据将来自服务器,这就是我在onClick中启动新活动的原因方法)。

2 个答案:

答案 0 :(得分:0)

您需要通过XML设置onclick操作(这适用于活动),或者您需要在代码中设置它(几乎就像您拥有它),但是分配给视图本身

我个人更喜欢在代码中定义点击操作。我认为在阅读项目时更有意义,你可以避免任何类似的问题。它也是推荐的方法,大多数示例代码和示例都是这样做的(参见Android Documentation

要通过代码定义点击,请执行以下操作:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.fragment_home, container, false);
    View OK3 = rootView.findViewById(R.id.rec_prod3); //pick a better name than i have though
    if (OK3 != null) {
        OK3.setOnClickListener(new View.OnclickListener() {
            Log.i("HomeFragment", "OK3");
            Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
            startActivity(intent3);
        });
    }

大多数示例使用此方法作为使用switch语句的替代方法,并且通过相同的方法指导每次单击都是不好的做法 - 实际上,您正在攻击Google为XML支持提供的快捷方式,以执行其不打算做的事情对于。有关为什么最好使用专用侦听器的更多信息,请查看继承与组合 - 作为规则&#34;有A&#34;总是节拍&#34;是A&#34;代码可读性和可维护性。

答案 1 :(得分:-1)

您正在为整个片段设置OnClickListener,而不是您在switch-statement中查询的实际视图。当然,从未达到具体的代码部分! 这种方法应该有效(并且officially supported by Googlewell received by users on Stack Overflow):

public class HomeFragment extends Fragment implements View.OnClickListener {

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Log.i("HomeFragment", "OK");
    View rootView = inflater.inflate(R.layout.fragment_home, container, false);
    rootView.findViewById(R.id.rec_prod1).setOnClickListener(this);
    rootView.findViewById(R.id.rec_prod2).setOnClickListener(this);
    rootView.findViewById(R.id.rec_prod3).setOnClickListener(this);
    return rootView;
}

@Override
public void onClick(View v) {
    Log.i("HomeFragment", "OK0");
    switch (v.getId()) {
    case R.id.rec_prod1:
        Log.i("HomeFragment", "OK1");
        Intent intent1 = new Intent(getActivity(), SingleItemActivity.class);
        startActivity(intent1);
        break;
    case R.id.rec_prod2:
        Log.i("HomeFragment", "OK2");
        Intent intent2 = new Intent(getActivity(), SingleItemActivity.class);
        startActivity(intent2);
        break;
    case R.id.rec_prod3:
        Log.i("HomeFragment", "OK3");
        Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
        startActivity(intent3);
        break;
    }
}
}

进一步阅读:

通过XML设置onClick也可以,但遗憾的是,只在活动中,而不是在片段中:在片段的父活动上调用该方法(参见How to handle button clicks using the XML onClick within Fragments)。

但是,上述方法还有一个缺点:onClick是公开的,因此可以从外部调用。例如,父活动可以调用

((View.OnClickListener) homeFragment).onClick(
    homeFragment.getView().findViewById(R.id.rec_prod1));

这将触发rec_prod1的onClick事件。 IMO,这种方法带来的可读性和便利性超过了这一点。当然,还有其他方法各有优缺点。最重要的是,为了防止这种公共访问,您可以为每个监听器创建一个匿名类(请参阅Nick的答案和its disadvantages)或使用以下代码:

public class HomeFragment extends Fragment {

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Log.i("HomeFragment", "OK");
    View rootView = inflater.inflate(R.layout.fragment_home, container, false);
    View.OnClickListener onClick = new RecProdClickListener();
    rootView.findViewById(R.id.rec_prod1).setOnClickListener(onClick);
    rootView.findViewById(R.id.rec_prod2).setOnClickListener(onClick);
    rootView.findViewById(R.id.rec_prod3).setOnClickListener(onClick);
    return rootView;
}

private class RecProdClickListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
        Log.i("HomeFragment", "OK0");
        switch (v.getId()) {
        case R.id.rec_prod1:
            Log.i("HomeFragment", "OK1");
            Intent intent1 = new Intent(getActivity(), SingleItemActivity.class);
            startActivity(intent1);
            break;
        case R.id.rec_prod2:
            Log.i("HomeFragment", "OK2");
            Intent intent2 = new Intent(getActivity(), SingleItemActivity.class);
            startActivity(intent2);
            break;
        case R.id.rec_prod3:
            Log.i("HomeFragment", "OK3");
            Intent intent3 = new Intent(getActivity(), SingleItemActivity.class);
            startActivity(intent3);
            break;
        }
    }
}
}

除了所有这些之外,几个匿名点击监听器将导致更多的内存使用和更长的初始化时间,而重复使用带有switch语句的点击监听器将使性能成为negligibly worse due to cyclomatic complexity

但你甚至可以混合使用不同的方法。最终,这取决于您的口味。讨论在什么情况下什么是最好的属于programmers.stackexchange并且肯定是Android开发中干净代码的一个有趣话题。