Java 检查片段当前是否可见或不可见
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43207043/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Check if fragment is currently visible or no
提问by Vikash Parajuli
I know there are lots of similar questions in StackOverflow but my question is little different.
我知道 StackOverflow 中有很多类似的问题,但我的问题几乎没有什么不同。
I have nested hierarchy of Fragments like in below structure:
我有嵌套的 Fragment 层次结构,如下所示:
Activity
|
|
AFragment
|
(ViewPager)
| |
| |
BFragment BFragment .....
|
(ViewPager)
| |
| |
CFragment CFragment ...
|
(ViewPager)
| |
| |
DFragment DFragment ...
Now i want to know that whether DFragment
is showing to user or not?
现在我想知道是否DFragment
向用户显示?
I tried lots of solution from StackOverflow but couldn't get sucess.
我从 StackOverflow 尝试了很多解决方案,但都没有成功。
What i tried is:
我试过的是:
I tried setUserVisibleHint()
but it returns true
for multiple DFragment
in above hierarchy which is a cause of ViewPager
我试过了,setUserVisibleHint()
但它在上面的层次结构中返回true
多个DFragment
,这是一个原因ViewPager
I also tried from these links: link1, link2, link3and so on... but did not got actual solution.
我也尝试从这些链接:link1,link2,link3等等......但没有得到实际的解决方案。
Waiting for help. Thank you.
等待帮助。谢谢你。
UPDATE
更新
Adapter Class
适配器类
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
回答by faisal iqbal
try this
尝试这个
@Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
}
else
{
}
}
回答by azizbekian
You can check, whether the View
that fragment inflated is visible on the device's screen:
您可以检查View
膨胀的片段是否在设备屏幕上可见:
Fragment fragment = ... // retrieve from `ViewPager`'s adapter.
View fragmentRootView = fragment.getView();
if (fragmentRootView != null && fragmentRootView.getGlobalVisibleRect(new Rect())) {
// fragment is visible
} else {
// fragment is not visible
}
getGlobalVisibleRect()
will return true
if part of the view is visible at the root level.
getGlobalVisibleRect()
true
如果视图的一部分在根级别可见,则将返回。
回答by Geek
You can override
setUserVisibleHint()
in each fragment where you want to check whether it is visible or not with a additional flag. For an example
您可以override
setUserVisibleHint()
在每个片段中使用附加标志检查它是否可见。举个例子
Java:
爪哇:
boolean isVisited = false;
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && !isVisited )
{
isVisited = true;
}
else if(isVisited)
{
// this fragment is already in front of user
}
}
I was having similar problem. Once I was need to load data from server to fragment
only when it was in-front of user. I solved it as above.
我遇到了类似的问题。曾经我需要将数据从服务器加载到fragment
仅当它在用户面前时。我按照上面的方法解决了。
Kotlin :
科特林:
private var isVisited: Boolean = false
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (isVisibleToUser && !isVisited!! )
{
isVisited = true;
}
else if(isVisited!!)
{
Toast.makeText(activity!!, "Location required", Toast.LENGTH_SHORT).show()
}
}
Hope it will help you as well.
希望它也能帮助你。
回答by Darshan Miskin
Give this a try..
试试这个..
The isVisible()
adds an extra layer of visibility check.
在isVisible()
增加了清晰视野检查的一个额外层。
ViewPager viewPager=(ViewPager)findViewById(R.id.view_pager);
final Fragment[] fragments={new DFragment(),new MyFragment()}; //add all the other fragment objects present in the view pager......
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if(fragments[position].isVisible()){
//Cool stuff to do.
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
回答by Reyansh Mishra
As far as I have tried I think this will work Please try and let me know. Do something like this in your activity.
据我尝试,我认为这会起作用请尝试让我知道。在你的活动中做这样的事情。
public boolean isFragmentVisible(SwipeAdapter swipeAdapter) {
SwipeAdapter swipeAdapterA = fragmentA.getViewPagerAdapter();
BFragment bFragment = (BFragment) swipeAdapterA.getFragment(0);
if (bFragment != null) {
SwipeAdapter swipeAdapterB = bFragment.getViewPagerAdapter();
CFragment cFragment = (CFragment) swipeAdapterA.getFragment(0);
if (cFragment != null) {
SwipeAdapter swipeAdapterC = cFragment.getViewPagerAdapter();
DFragment dFragment = (DFragment) swipeAdapterA.getFragment(0);
if (dFragment != null) {
return dFragment.isFragmentVisible();
}
}
}
return false;
}
Use this class as your viewpager adapter
使用这个类作为你的 viewpager 适配器
class SwipeAdapter extends FragmentPagerAdapter {
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;
private String mPagetile[];
public SwipeAdapter(FragmentManager fm, Context context) {
super(fm);
mPagetile = context.getResources().getStringArray(R.array.pageTitle);
mFragmentManager = fm;
mFragmentTags = new HashMap<>();
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new "Your_fragment";
default:
break;
}
return null;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return mFragmentManager.findFragmentByTag(tag);
}
@Override
public CharSequence getPageTitle(int position) {
return mPagetile[position];
}
@Override
public int getCount() {
return "Number of fragments";
}
}
Now in your DFragment do this
现在在您的 DFragment 中执行此操作
boolean isVisible=false;
@Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
isVisible=menuVisible;
}
public boolean isFragmentVisible(){
return isVisible;
}
Let me know if it worked if not let me know the reason.
如果不让我知道原因,请告诉我它是否有效。
回答by Nitin Patel
We can easily map which fragment is now visible using mViewPager.getCurrentItem()
method. This method gives int
value number from which we can find the current fragment.
我们可以使用mViewPager.getCurrentItem()
方法轻松映射现在可见的片段。此方法给出了int
我们可以从中找到当前片段的值 number。
-- For access and get this method result we have two options:
-- 对于访问和获取此方法结果,我们有两个选择:
- make
Static
viewPager instance in activity and use wherever we want - again make
viewPager
instance in fragment (findViewById()
)
Static
在活动中创建viewPager 实例并在我们想要的任何地方使用- 再次
viewPager
在片段 (findViewById()
) 中创建实例
and using one from above two methods getCurrentItem()
in fragment to find which fragment is visible now.
并getCurrentItem()
在片段中使用上述两种方法中的一种来查找现在哪个片段可见。
For example,
例如,
- In MainActivity (activity which is used for ViewPager) define
- 在 MainActivity(用于 ViewPager 的活动)中定义
public static ViewPager mViewPager;
public static ViewPager mViewPager;
- In Fragment,
MainActivity.mViewPager.getCurrentItem()
to get current fragment
- 在片段中,
MainActivity.mViewPager.getCurrentItem()
获取当前片段
Also, method that shows which fragment is visible:
此外,显示哪个片段可见的方法:
public void whichIsVisible() {
String msg = "";
int curFragNo = MainActivity.mViewPager.getCurrentItem();
switch (curFragNo) {
case 0:
msg = "AFragment is visible.";
break;
case 1:
msg = "BFragment is visible.";
break;
case 2:
msg = "CFragment is visible.";
break;
case 3:
msg = "DFragment is visible.";
break;
}
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
(2) For non-static use,
(2) 对于非静态用途,
- get
viewPager
instance in fragment by below code,
viewPager
通过以下代码获取片段中的实例,
viewPager=(ViewPager) view.getRootView().findViewById(R.id.container);
viewPager=(ViewPager) view.getRootView().findViewById(R.id.container);
and then
进而
viewPager.getCurrentItem()
to get index and find current visible fragment as per use.
viewPager.getCurrentItem()
获取索引并根据使用查找当前可见片段。
回答by Nouman Ghaffar
The most simplest sloution might be.
In onCreate
of your DF fragment
store a boolean
in preferences
. i.e Key = is_fragment_visible_to_user
. And change it to true
.
And in onStop
or onDestroy
(whichever fills your requirement) change, it's value to false
. With this, you can check it easily by accessing the preferences value. In the case of multiple instances, you can store the tag with the another key.
最简单的可能是。在onCreate
您的DF fragment
商店boolean
中preferences
。即Key = is_fragment_visible_to_user
。并将其更改为true
. 在onStop
or onDestroy
(以满足您的要求为准)更改中,它对false
. 有了这个,您可以通过访问首选项值轻松检查它。在多个实例的情况下,您可以使用另一个键存储标签。
回答by insomniac
When I had a similar problem I solved it by using this hacky method 'going under the hood' like
当我遇到类似的问题时,我通过使用这种“隐藏在幕后”的hacky方法解决了它
Inside your FragmentPagerAdapter
(s) add this function.
在您的FragmentPagerAdapter
(s)中添加此功能。
public Fragment getActiveFragment(ViewPager container, int position) {
String name = makeFragmentName(container.getId(), position);
return fm.findFragmentByTag(name);
}
private static String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
It is not the most graceful solution but as long as it works
这不是最优雅的解决方案,但只要它有效
CAUTION
警告
This is a private method internal to ViewPagerthat could change at any time or for any OS version.
这是ViewPager内部的私有方法,可以随时更改或针对任何操作系统版本进行更改。
回答by Kilnn
Although the past for so long, but I still want to give my program, because I found that get visible state of Fragment is indeed not easy. Based on your request, you need to solve these three questions:
虽然过去这么久,但我还是想给我的程序,因为我发现得到Fragment的可见状态确实不容易。根据您的要求,您需要解决以下三个问题:
- How to use FragmentPagerAdapter or FragmentStatePagerAdapter
- How to determine the visible state of Fragment
- How to handle when the Fragment is nested
- 如何使用 FragmentPagerAdapter 或 FragmentStatePagerAdapter
- 如何确定 Fragment 的可见状态
- Fragment嵌套时如何处理
At first, i defined a base Adapter help me to get the Fragment in ViewPager.If you Fragment's position and type is changeable in ViewPager, you must use public int getItemPosition(Object object) method
and public Fragment getItem(int position)
method to get the right position.
首先,我定义了一个基本的适配器来帮助我在 ViewPager 中获取 Fragment。如果您在 ViewPager 中 Fragment 的位置和类型是可变的,则必须使用 public int getItemPosition(Object object) method
和public Fragment getItem(int position)
方法来获取正确的位置。
/**
* Created by Kilnn on 2017/7/12.
* A abstract FragmentStatePagerAdapter which hold the fragment reference.
*/
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private SparseArray<WeakReference<Fragment>> registeredFragments = new SparseArray<>();
public SmartFragmentStatePagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, new WeakReference<>(fragment));
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
WeakReference<Fragment> reference = registeredFragments.get(position);
return reference != null ? reference.get() : null;
}
}
At then ,i define a base Fragment to handle the visible state.But there is a little flaw is that you must specify same switch type for one set of fragment .
然后,我定义了一个基础 Fragment 来处理可见状态。但是有一个小缺陷是您必须为一组 Fragment 指定相同的开关类型。
import android.support.annotation.IntDef;
import android.support.v4.app.Fragment;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by Kilnn on 2017/7/12.
* A smart fragment know itself's visible state.
*/
public abstract class SmartFragment extends Fragment {
private boolean isFragmentVisible;
@Override
public void onResume() {
super.onResume();
int switchType = getSwitchType();
if (switchType == ATTACH_DETACH) {
notifyOnFragmentVisible();
} else if (switchType == SHOW_HIDE) {
if (!isHidden()) {
notifyOnFragmentVisible();
}
} else if (switchType == VIEW_PAGER) {
//If the parent fragment exist and hidden when activity destroy,
//when the activity restore, The parent Fragment will be restore to hidden state.
//And the sub Fragment which in ViewPager is also be restored, and the onResumed() method will callback.
//And The sub Fragment's getUserVisibleHint() method will return true if it is in active position.
//So we need to judge the parent Fragment visible state.
if (getUserVisibleHint() && isParentFragmentVisible()) {
notifyOnFragmentVisible();
}
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
int switchType = getSwitchType();
if (switchType == VIEW_PAGER) {
if (isVisibleToUser) {
//If ViewPager in ViewPager , the sub ViewPager will call setUserVisibleHint before onResume
if (isResumed()) {
notifyOnFragmentVisible();
}
} else {
notifyOnFragmentInvisible();
}
}
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
int switchType = getSwitchType();
if (switchType == SHOW_HIDE) {
if (hidden) {
notifyOnFragmentInvisible();
} else {
//Just judge for safe
if (isResumed()) {
notifyOnFragmentVisible();
}
}
}
}
@Override
public void onPause() {
super.onPause();
notifyOnFragmentInvisible();
}
private boolean isParentFragmentVisible() {
Fragment parent = getParentFragment();
if (parent == null) return true;
if (parent instanceof SmartFragment) {
return ((SmartFragment) parent).isFragmentVisible();
} else {
//TODO May be can't get the correct visible state if parent Fragment is not SmartFragment
return parent.isVisible();
}
}
public boolean isFragmentVisible() {
// Don't judge the state of the parent fragment,
// because if the parent fragment visible state changes,
// you must take the initiative to change the state of the sub fragment
// return isFragmentVisible && isParentFragmentVisible();
return isFragmentVisible;
}
public void notifyOnFragmentVisible() {
if (!isFragmentVisible) {
onFragmentVisible();
isFragmentVisible = true;
}
}
public void notifyOnFragmentInvisible() {
if (isFragmentVisible) {
onFragmentInvisible();
isFragmentVisible = false;
}
}
/**
* If this method callback, the Fragment must be resumed.
*/
public void onFragmentVisible() {
}
/**
* If this method callback, the Fragment maybe is resumed or in onPause().
*/
public void onFragmentInvisible() {
}
/**
* Fragments switch with attach/detach(replace)
*/
public static final int ATTACH_DETACH = 0;
/**
* Fragments switch with show/hide
*/
public static final int SHOW_HIDE = 1;
/**
* Fragments manage by view pager
*/
public static final int VIEW_PAGER = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ATTACH_DETACH, SHOW_HIDE, VIEW_PAGER})
public @interface SwitchType {
}
@SwitchType
public abstract int getSwitchType();
}
At last, hand the sub Fragment visible state in the parent Fragment if nested use.
最后,如果嵌套使用,则在父 Fragment 中传递子 Fragment 可见状态。
public class ParentFragment extends SmartFragment{
....
@Override
public void onFragmentVisible() {
super.onFragmentVisible();
SmartFragment fragment = (SmartFragment) mAdapter.getRegisteredFragment(mViewPager.getCurrentItem());
if (fragment != null) {
fragment.notifyOnFragmentVisible();
}
}
@Override
public void onFragmentInvisible() {
super.onFragmentInvisible();
SmartFragment fragment = (SmartFragment) mAdapter.getRegisteredFragment(mViewPager.getCurrentItem());
if (fragment != null) {
fragment.notifyOnFragmentInvisible();
}
}
...
}
I have test with attach/detach, show/hide ,and three layers ViewPager nested. It work fine. Maybe I should have done more testing, but for me it was enough.
我对附加/分离、显示/隐藏和三层 ViewPager 嵌套进行了测试。它工作正常。也许我应该做更多的测试,但对我来说已经足够了。
回答by Mohammad Reza Norouzi
public static boolean isFragmentVisible(Fragment fragment) {
Activity activity = fragment.getActivity();
View focusedView = fragment.getView().findFocus();
return activity != null
&& focusedView != null
&& focusedView == activity.getWindow().getDecorView().findFocus();
}