jjzjj

android - 在主/从流程中切换 fragment

coder 2023-12-17 原文

我正在尝试使用 fragment 创建一个具有主/详细流程的应用程序。选择一个项目将打开一个细节 fragment ,然后可以“打开”另一个 fragment 并将其添加到返回堆栈。

我重命名了类以帮助说明它们的作用。

public class ListOfDetails extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
    }

    //Callback method indicating that an item with the given ID was selected.
    public void onItemSelected(String id) {
        // Performing logic to determine what fragment to start omitted

        if (ifTwoPanes()) {
            Fragment fragment = new DetailFragmentType1();
            getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit();
        } else {
            Intent newIntent = new Intent(this, SinglePaneFragmentWrapper.class);
            newIntent.putExtra("id", id);
            startActivity(newIntent);
        }
    }

    // My attempt at making it possible to change displayed fragment from within fragments
    public void changeDetailFragment(Fragment fragment) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        transaction.addToBackStack(null);
        transaction.replace(R.id.aContainer, fragment);
        transaction.commit();
    }
}

其中一个细节 fragment 的示例。在不同的情况下可能会创建许多不同的 fragment 。

public class DetailFragmentType1 extends Fragment {
    private ListOfDetails parent;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Activity a = getActivity();
        if (a instanceof ListOfDetails) {
            parent = (ListOfDetails) a;
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Button aButton = (Button) getActivity().findViewById(R.id.aButton);
        aButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                parent.changeDetailFragment(new SubDetailFragment());
            }
        });
    }
}

在打电话时,包装器 Activity 用于保存 fragment

public class SinglePaneFragmentWrapper extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Duplicate logic must be performed to start fragment
        // Performing logic to determine what fragment to start omitted
        String id = getIntent().getStringExtra("id");
        if(id == "DetailFragmentType1") {
            Fragment fragment = new DetailFragmentType1();
            getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit();
        } else {
            ...
        }
    }
}

在这种情况下,更改详细信息 Pane 中打开的 fragment 的正确方法是什么?我的方法在使用两个 Pane 时感觉像是一个 hack,甚至在仅使用一个 Pane 时也不起作用,因为 SinglePaneFragmentWrapper 中的 getParent() 返回 null,使我无法调用 parent.changeDetailFragment()

这是一个复杂的问题,希望我解释得很好。如果我错过了什么,请告诉我。谢谢

最佳答案

围绕这个有很多观点和很多方法。我认为在这种情况下,问题是“谁负责更改 fragment ?”从表面上看,按钮上的监听器似乎是显而易见的位置,但 fragment 不应该知道它托管在什么地方(一个症状是从 getParent() 中得到像 null 这样的不良结果)。

在您的情况下,我建议您在父级中实现一个“监听器”接口(interface)并从 fragment 中“通知”。当父级收到通知时,它会更改 fragment 。这样 fragment 就不会改变自己(所以不需要知道如何改变)..所以..对于你的情况..

添加新界面:

public interface FragmentChangeListener {
  void onFragmentChangeRequested(Fragment newFragment);
}

在您的 ListOfDetails Activity 中实现接口(interface)

public class ListOfDetails extends FragmentActivity implements FragmentChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
}

//Callback method indicating that an item with the given ID was selected.
public void onItemSelected(String id) {
    // Performing logic to determine what fragment to start omitted

    if (ifTwoPanes()) {
        Fragment fragment = new DetailFragmentType1();
        getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit();
    } else {
        Intent newIntent = new Intent(this, SinglePaneFragmentWrapper.class);
        newIntent.putExtra("id", id);
        startActivity(newIntent);
    }
}

// My attempt at making it possible to change displayed fragment from within fragments
public void changeDetailFragment(Fragment fragment) {
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    transaction.addToBackStack(null);
    transaction.replace(R.id.aContainer, fragment);
    transaction.commit();
}

// This is the interface implementation that will be called by your fragments
void onFragmentChangeRequested(Fragment newFragment) {
    changeDetailFragment(newFragment);
}

}

为细节 fragment 添加了监听器

public class DetailFragmentType1 extends Fragment {

    private FragmentChangeListener fragmentChangeListener;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Actually you might not have an activity here.. you should probably be 
        // doing this in onAttach
        //Activity a = getActivity();
        //if (a instanceof ListOfDetails) {
        //    parent = (ListOfDetails) a;
        //}
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        Button aButton = (Button) getActivity().findViewById(R.id.aButton);
        aButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
               // parent.changeDetailFragment(new SubDetailFragment());
               notifyFragmentChange(new SubDetailFragment());
            }
        });
    }

    @Override
    public void onAttach(Activity activity) {
      // This is called when the fragment is attached to an activity..
      if (activity instanceof FragmentChangeListener) {
          fragmentChangeListener = (FragmentChangeListener) activity;
      } else {
         // Find your bugs early by making them clear when you can...
         if (BuildConfig.DEBUG) {
           throw new IllegalArgumentException("Fragment hosts must implement FragmentChangeListener");
         }
      }
    }

    private void notifyFragmentChange(Fragment newFragment) {
      FragmentChangeListener listener = fragmentChangeListener;
      if (listener != null) {
         listener.onFragmentChangeRequested(newFragment);
      }
    }
}

并为您的单 Pane Activity 实现相同的界面...

public class SinglePaneFragmentWrapper extends FragmentActivity implements FragmentChangeListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Duplicate logic must be performed to start fragment
        // Performing logic to determine what fragment to start omitted
        String id = getIntent().getStringExtra("id");
        if(id == "DetailFragmentType1") {
            Fragment fragment = new DetailFragmentType1();
            getSupportFragmentManager().beginTransaction().replace(R.id.aContainer, fragment).commit();
        } else {
            ...
        }
    }
// My attempt at making it possible to change displayed fragment from within fragments
public void changeDetailFragment(Fragment fragment) {
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
    transaction.addToBackStack(null);
    transaction.replace(R.id.aContainer, fragment);
    transaction.commit();
}

// This is the interface implementation that will be called by your fragments
void onFragmentChangeRequested(Fragment newFragment) {
    changeDetailFragment(newFragment);
}

}

请注意您的单 Pane 和多 Pane Activity 之间的相似性。这表明您可以将所有重复的代码(changefragment 等)放入它们都扩展的单个 Activity 中,或者它们可能是相同的具有不同布局的 Activity ...

希望对您有所帮助,祝您好运。

问候, 希杰

关于android - 在主/从流程中切换 fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15940239/

有关android - 在主/从流程中切换 fragment的更多相关文章

  1. ruby-on-rails - Ruby on Rails with Haml - 如何从 erb 切换 - 2

    我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h

  2. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  3. ruby-on-rails - 语言环境不在 Rails 4 中切换 - 2

    我的Rails应用程序在rails4.0.2上,我在使用locale变量和params[:locale]切换翻译时遇到问题官方railsguide.我在mysite有一个单页网站.我的国际化路线:scope"(:locale)",locale:/en|de/do#myrouteshereend我的应用程序Controllerbefore_filter:set_localedefset_localeI18n.locale=params[:locale]||I18n.default_locale#Rails.application.routes.default_url_options[:l

  4. jquery - 在 Rails 中从原型(prototype)切换到 jquery,助手呢? - 2

    我目前从prototype切换到jquery主要是为了支持简单的ajax文件上传。我使用:https://github.com/indirect/jquery-rails95%的javascript代码是由railshelper编写的,例如:-remote_function-render:updatedo|page|-page.replace_html'id',:partial=>'content'-page['form']['name']=something-page.visual_effect:highlight,'head_success'...我知道我必须为Jquery重写5%

  5. 微信小程序切换云环境 - 2

    在开发微信小程序的时候,我们可能需要开发环境和测试环境,或者其他环境,下面是切换环境的方法。首先需要明确的是:前端的页面代码是不区分环境的,环境的区分指的是云函数、云数据库、云存储这些。1、更改云函数的使用云环境这里我们从cloud1更改为test-cloud,这个改完是没有用的,因为在前端代码指定了使用的云环境。cloudfunctions文件和miniprogram文件虽然都在一个目录下,但是这两个没有直接联系。2、在evList.js中添加自己云环境evList.js存储了云环境列表,这里把test-cloud加到这个列表里,需要填写envId和alias,参照cloud1写就行。3、更

  6. 等保工作流程和明细 - 2

    一、系统定级信息系统运营使用单位按照等级保护管理办法和定级指南,自主确定信息系统的安全保护等级。有上级主管部门的,应当经上级主管部门审批。跨省或全国统一联网运行的信息系统可以由其主管部门统一确定安全保护等级。定级需要根据信息系统的实际情况合理定级。二、系统备案第二级以上信息系统定级单位到所在地设区的市级以上公安机关办理备案手续。省级单位到省公安厅网安总队备案,各地市单位一般直接到市级网安支队备案,也有部分地市区县单位的定级备案资料是先交到区县公安网监大队的,具体根据各地市要求来。信息系统运营、使用单位或者其主管部门应当在信息系统安全保护等级确定后30日内,到公安机关办理备案手续。三、初次测评信

  7. 2023爱分析·流程中台市场厂商评估报告:微宏科技 - 2

     目录1. 研究范围定义2. 流程中台市场分析3. 厂商评估:微宏科技4. 入选证书 1.   研究范围定义近年来,随着外部市场环境快速变化、客户需求愈发多样,企业逐渐意识到,自身业务需要更加敏捷、高效,具备根据市场需求快速迭代的能力。业务流程的自动化能够帮助企业实现业务的敏捷高效,因此受到越来越多企业的关注。企业的“自动化武器库”品类丰富,包括低/零代码平台、RPA、BPM、AI等。企业可以使用多项自动化工具,但结果往往是各项自动化工具处于各自的“自动化烟囱”之中,仅能实现碎片式自动化。例如,某企业的IT团队可能在使用低代码平台、财务团队可能在使用RPA、呼叫中心则可能在使用聊天机器人。自动

  8. ruby - 在 rspec 中测试多步骤工作流程 - 2

    我想了解使用rspec测试多步骤工作流的习惯用法或最佳实践。我们以“购物车”系统为例,其中的购买流程可能是当用户提交购物篮并且我们没有使用https时,重定向到https当用户提交购物篮并且我们使用https并且没有cookie时,创建并显示一个新的购物篮并发回cookie当用户提交到购物车并且我们使用https并且有一个有效的cookie并且新商品与第一个商品用于不同的产品时,向购物车添加一行并显示这两行当用户提交到购物篮并且我们使用https并且有一个有效的cookie并且新商品与之前的商品相同时,增加该购物篮行的数量并显示这两条线当用户点击购物车页面上的“结帐”并使用https并

  9. ruby-on-rails - 如何在 Controller Action 中切换 bool 属性 - 2

    我有一个操作可以简单地将#active属性切换到相反的bool状态:如果@blog.active==true然后更新它到非事件如果@blog.active==false然后更新它到事件我在Controller中获得了以下自定义操作,但必须有一些Rails方法才能更优雅地执行此操作:classBlogsController是否有一种Rails方法可以将bool属性更新为相反的bool状态? 最佳答案 ActiveRecord具有执行此操作的toggle和toggle!方法。请记住,toggle!方法会跳过验证检查。classBlogs

  10. ruby - 切换到 cucumber , capybara 中的弹出窗口 - 2

    在RSpec中我可以使用这样的代码切换到弹出窗口,link,我怎么能在cucumber步骤中做这样的事情?login_window=page.driver.find_window('PPA_identity_window')main_window=page.driver.find_window('')#Weusethistoexecutethenextinstructionsinthepopupwindowpage.within_window(login_window)do#Normallyfillintheformandloginfill_in'email',:with=>""fil

随机推荐