我希望在后台中获取最后一个片段,或者在tab b_1
中显示当前的片段对我来说是一样的。如下图所示,我有一个ViewPager,另一个是内部tab b
。因此,显示了四个当前片段。
问题:如何获取Fragment 2
实例?
我已经看到了另一种解决方案,但没有一种适用于这种情况。
注释: ViewPager中托管的片段不是必需的。我可以在一个标签中再打开两个片段。
使用这种方法,我得到所有当前可见的片段,但不是我想要的特定片段。
public ArrayList<Fragment> getVisibleFragment() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
ArrayList<Fragment> visibleFragments = new ArrayList<>();
if (fragments != null) {
for (Fragment fragment : fragments) {
if (fragment != null && fragment.isVisible())
visibleFragments.add(fragment);
}
}
return visibleFragments;
}
一些有趣的代码
activity_main.xml中
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static ViewPagerAdapter adapter;
private static ViewPager viewPager;
private TabLayout tabLayout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager();
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
setupTabIcons();
}
private void setupViewPager() {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
// Wrap with HostFragment to get separate tabbed nagivation.
adapter.addFrag(HostFragment.newInstance(new Fragment1()), null);
adapter.addFrag(HostFragment.newInstance(new RootFragment2()), null);
adapter.addFrag(HostFragment.newInstance(new Fragment4()), null);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(2);
}
public void openNewFragment(Fragment fragment) {
HostFragment hostFragment = (HostFragment) adapter.getItem(viewPager.getCurrentItem());
hostFragment.replaceFragment(fragment, true);
}
}
fragment_host.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/hosted_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
HostFragment.java
/**
* This class implements separate navigation for a tabbed viewpager.
*
* Based on https://medium.com/@nilan/separate-back-navigation-for-
* a-tabbed-view-pager-in-android-459859f607e4#.u96of4m4x
*/
public class HostFragment extends BackStackFragment {
private Fragment fragment;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_host, container, false);
if (fragment != null) {
replaceFragment(fragment, false);
}
return view;
}
public void replaceFragment(Fragment fragment, boolean addToBackstack) {
if (addToBackstack) {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit();
} else {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit();
}
}
public static HostFragment newInstance(Fragment fragment) {
HostFragment hostFragment = new HostFragment();
hostFragment.fragment = fragment;
return hostFragment;
}
public Fragment getFragment() {
return fragment;
}
}
fragment2_root.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fragment2_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="@+id/tab2_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"/>
<android.support.v4.view.ViewPager
android:id="@+id/tab2_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</LinearLayout>
RootFragment2.java
public class RootFragment2 extends Fragment {
private ViewPagerAdapter adapter;
private ViewPager viewPager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout for this fragment.
View root = inflater.inflate(R.layout.fragment2_root, container, false);
viewPager = (ViewPager) root.findViewById(R.id.tab2_viewpager);
setupViewPager(viewPager);
TabLayout tabLayout = (TabLayout) root.findViewById(R.id.tab2_tabs);
tabLayout.setupWithViewPager(viewPager);
return root;
}
private void setupViewPager(ViewPager viewPager) {
adapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager());
// Wrap with HostFragment to get separate tabbed nagivation.
adapter.addFrag(HostFragment.newInstance(new Fragment2()), null);
adapter.addFrag(HostFragment.newInstance(new Fragment3()), null);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(1);
}
public ViewPagerAdapter getAdapter() {
return adapter;
}
public ViewPager getViewPager() {
return viewPager;
}
}
答案 0 :(得分:32)
首先在SparseArray
&#39;中定义ViewPagers
。适配器如下。在这个数组中,我们将保留片段的实例。
SparseArray<Fragment> registeredFragments = new SparseArray<>();
并覆盖您的适配器&#39; instantiateItem
方法。
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
同时覆盖destroyItem
ViewPagers
方法
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
定义一种新方法来获取ViewPager
Fragments
个实例。
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
最后设置为PageChangeListener
添加ViewPagers
:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
// Here's your instance
YourFragment fragment =(YourFragment)yourPagerAdapter.getRegisteredFragment(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
我希望这会帮助你。祝你好运。
编辑:对不起,我无法准确理解您计划做什么,但如果您需要保留子片段(b_1,b_2)实例,您可以为您的活动定义一种方法,例如
public void setCurrentFragment(Fragment fragment){
this.currentFragment = fragment;
}
在您的子视图寻呼机适配器中,您可以调用此方法,如下所示:
subViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
// Here's your instance
YourFragment fragment =(YourFragment)yourSubPagerAdapter.getRegisteredFragment(position);
((MyActivity)getActivity).setCurrentFragment(fragment);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
通过这种方式,您可以保留一个实例和顶部片段。
答案 1 :(得分:3)
在对DEADMC发表评论之后,我决定用额外的内存来实现它,在列表中保存开放的片段。
我解释我的解决方案。我有两种类型的特殊片段,主机和 root 。主机片段是选项卡的init。 Root Fragments是那些持有ViewPager的片段。在这种情况下,tab_b
有一个带有内部ViewPager的Root Fragment。
对于每个标签,对于每个 HostFragment ,我添加了一个列表fragments
以保存在此标签中打开的片段。还有一个方法getCurrentFragment
,可以在此选项卡中显示最后一个。
public class HostFragment extends BackStackFragment {
private ArrayList<Fragment> fragments = new ArrayList<>();
public Fragment getCurrentFragment() {
return fragments.get(fragments.size() - 1);
}
还需要一种删除此选项卡中显示的最后一个片段的方法,以保持真实状态。后退按钮需要重定向到此方法。
public void removeCurrentFragment() {
getChildFragmentManager().popBackStack();
fragments.remove(fragments.size() - 1);
}
还需要更改以前的方法,以插入打开到列表中的新片段。
public void replaceFragment(Fragment fragment, boolean addToBackstack) {
// NEW: Add new fragment to the list.
fragments.add(fragment);
if (addToBackstack) {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).addToBackStack(null).commit();
} else {
getChildFragmentManager().beginTransaction().replace(R.id.hosted_fragment, fragment).commit();
}
}
public static HostFragment newInstance(Fragment fragment) {
HostFragment hostFragment = new HostFragment();
// NEW: Add first fragment to the list.
hostFragment.fragments.add(fragment);
return hostFragment;
}
} // HostFragment.
RootFragment 是由拥有ViewPager的片段实现的接口。
public interface RootFragment {
/**
* Opens a new Fragment in the current page of the ViewPager held by this Fragment.
*
* @param fragment - new Fragment to be opened.
*/
void openNewFragment(Fragment fragment);
/**
* Returns the fragment displayed in the current tab of the ViewPager held by this Fragment.
*/
Fragment getCurrentFragment();
}
然后,实施将是:
MainActivity 不是片段,但我实现了 RootFragment 界面。
public class MainActivity extends AppCompatActivity implements RootFragment {
private void setupViewPager() {
adapter = new ViewPagerAdapter(getSupportFragmentManager());
// Wrap with HostFragment to get separate tabbed nagivation.
adapter.addFrag(HostFragment.newInstance(new Fragment1()), null);
adapter.addFrag(new RootFragment2(), null); // This is a Root, not a Host.
adapter.addFrag(HostFragment.newInstance(new Fragment4()), null);
viewPager.setAdapter(adapter);
// 2 because TabLayout has 3 tabs.
viewPager.setOffscreenPageLimit(2);
}
@Override
public void openNewFragment(Fragment fragment) {
Fragment hosted = adapter.getItem(viewPager.getCurrentItem());
// Replace the fragment of current tab to [fragment].
if (hosted instanceof HostFragment) {
((HostFragment) hosted).replaceFragment(fragment, true);
// Spread action to next ViewPager.
} else {
((RootFragment) hosted).openNewFragment(fragment);
}
}
@Override
public Fragment getCurrentFragment() {
Fragment hosted = adapter.getItem(viewPager.getCurrentItem());
// Return current tab's fragment.
if (hosted instanceof HostFragment) {
return ((HostFragment) hosted).getCurrentFragment();
// Spread action to next ViewPager.
} else {
return ((RootFragment) hosted).getCurrentFragment();
}
}
}
和 RootFragment2
public class RootFragment2 extends Fragment implements RootFragment {
private void setupViewPager(ViewPager viewPager) {
adapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager());
// Wrap with HostFragment to get separate tabbed nagivation.
adapter.addFrag(HostFragment.newInstance(new Fragment2()), null);
adapter.addFrag(HostFragment.newInstance(new Fragment3()), null);
viewPager.setAdapter(adapter);
// 1 because TabLayout has 2 tabs.
viewPager.setOffscreenPageLimit(1);
}
@Override
public void openNewFragment(Fragment fragment) {
((HostFragment) adapter.getItem(viewPager.getCurrentItem())).replaceFragment(fragment, true);
}
@Override
public Fragment getCurrentFragment() {
return ((HostFragment) adapter.getItem(viewPager.getCurrentItem())).getCurrentFragment();
}
}
然后,我只需要打电话:
((MainActivity)getActivity())。getCurrentFragment();
答案 2 :(得分:0)
您可以创建包含// in app.js file, remove module name :
define(["angular", "angularRoute","angularAnimate"], function(angular) {
var WalletHubApp = angular.module('WalletHubApp', ['ui.router','ngAnimate']);
WalletHubApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/walletHub/1/');
$stateProvider
.state('test', {
url: '/walletHub/:id/{folderPath:[a-zA-Z0-9/]*}',
templateUrl: function ($stateParams){
return "templates/"+$stateParams.id + '.html';
},
controllerProvider: function($stateParams) {
console.log($stateParams)
var ctrlName = $stateParams.id + "Controller";
return ctrlName;
}
});
});
return WalletHubApp;
});
// in controller file change WalletHubApp to app
define(['app'], function(WalletHubApp) {
WalletHubApp.controller('1Controller', function ($scope,$stateParams,$stateParams,$state,$http) {
$http.get('sample.json')
.then(function(res){
$scope.persons = res.data
});
var parts = $stateParams.folderPath.split('/')
$scope.params = false;
if(parts[0] != "")
{
$scope.parts = parts;
$scope.params = true;
}
})
return;
});
方法的CustomFragment
类,并从getClassName
类扩展。然后从Fragment
类而不是RootFragment2
扩展所有片段,例如CustomFragment
。
所以你可以得到这样的片段:
Fragment
答案 3 :(得分:0)
我会做那样的事情:
<强> 1 即可。创建这样的界面。
public interface ReturnMyself {
Fragment returnMyself();
}
<强> 2 即可。 ViewPagers中的所有片段都应该实现这一个。
第3 即可。将OnPageChangeListener
添加到主VP。所以你总会知道当前的位置。
<强> 4 即可。添加OnPageChangeListener
您的内部VP,以便您知道屏幕上有哪一个。
<强> 5 即可。向您的适配器(主要和内部)添加方法,该方法从传递给它的列表中返回您的片段。
public ReturnMyself getReturnMyselfAtPosition()
<强> 6 即可。所有片段都应在returnMyself()
<强> 7 即可。具有内部片段的片段应该返回给自己类似的东西。
Fragment returnMyself() {
return this.myInnerFragmentAdapter.getReturnMyselfAtPosition().returnMyself();
}
<强> 8 即可。从您刚刚调用的主要片段/活动开始。
this.adapter.getReturnMyselfAtPosition().returnMyself();
你得到了你现在的片段。