- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在 OnCreate 上添加选项卡时没有问题,正常添加选项卡,但在 LiveDataObserver 的 onChange 回调上添加选项卡时..没有任何反应。
我有一个带有 2 个片段的 ViewPager,在第二个片段内我有第二个 Viewpgaer 和另外 2 个 Fragemnt,第二个 vp 有一个 com.google.android.material.tabs.TabLayout 但 TabLayout 不通过 .setupWithViewPager 耦合()。
编辑:配置如下:
MainActivity (Nav) -> MainFrag (ViewPager) -> ChildFrag (at 1st pos)...<- 这是 TabLayout
继续:
此 TabLayout 仅显示第二个最内部 viewPager 的内容,这意味着它应该只显示 2 个选项卡,仅此而已。
但我想通过 LiveData 回调添加这两个选项卡。
我特别不希望它们(viewpager 和 tablayout)耦合,因为我希望片段创建一次,但我也希望选项卡看起来就像用户正在动态创建它们一样。
如果我创建 Fragemtns 的唯一目的是添加选项卡,那么每次完成此操作时,我都会面临从数据库获取信息的风险,即使用户选择相同的选项两次也是如此。
此外,如果片段已经构造好,分页就会变得平滑。我不惜一切代价避免使用notifyDataSetChanged(),因为我不喜欢数据如何通过该选项传输,这是主要原因。
所以我想在LiveData的onChange中添加.addTab(),这样我就可以使用LiveData提供的标题创建选项卡。
然而什么也没发生
<com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:tabSelectedTextColor="@android:color/white"
app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent"
app:tabTextColor="@android:color/black"
>
这就是 XML
public class FlyHighSubFragment extends Fragment {
private WeakReference<FlyHighActivity> mContextWeakReference;
private MySubFragmentPagerAdapter mAdapter;
private FragmentFlyhighSubBinding binding;
private TabLayout mTabLayout;
private SharedViewModel mSharedViewModel;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof FlyHighActivity) {
mContextWeakReference = new WeakReference<>((FlyHighActivity)context);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater,
R.layout.fragment_flyhigh_sub, container, false);
mAdapter = new MySubFragmentPagerAdapter(getChildFragmentManager());
binding.mainContainer.setAdapter(mAdapter);
mTabLayout = binding.tablayout;
mTabLayout.addOnTabSelectedListener(new TabLayout.BaseOnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
binding.mainContainer.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
binding.mainContainer.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout));
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSharedViewModel = ViewModelProviders.of(mContextWeakReference.get()).get(SharedViewModel.class);
/*called on the process of going from page [0][0] to page [1][0]*/
mSharedViewModel.getUserName().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
mTabLayout.addTab(mTabLayout.newTab().setText(s));
}
});
/*called on the process of going from [1][0] to [1][1]*/
mSharedViewModel.getSessionTitle().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
mTabLayout.addTab(mTabLayout.newTab().setText(s));
}
});
}
}
编辑:
我的SharedViewModel:
public class SharedViewModel extends ViewModel {
private static final String TAG = "SharedViewModel";
/*Each one of this Strings are passed from Fragment to Fragment, some of them trigger a Firebase listener, others provide view data for the Fragment.*/
/*All of them do their job properly, even the ones called inside the FlyHighSubFragment which is the Fragment that shelters the TabLayout*/
private MutableLiveData<String> uId = new MutableLiveData<>();
private MutableLiveData<String> userName = new MutableLiveData<>();
private MutableLiveData<String> chatRef = new MutableLiveData<>();
private MutableLiveData<String> sessionTitle = new MutableLiveData<>();
private MutableLiveData<Sessions> session = new MutableLiveData<>();
public SharedViewModel() {
}
public MutableLiveData<Sessions> getSession() {
return session;
}
public void setSession(Sessions session) {
this.session.setValue(session);
}
public MutableLiveData<String> getSessionTitle() {
return sessionTitle;
}
public void setSessionTitle(String sessionTitle) {
this.sessionTitle.setValue(sessionTitle);
}
public MutableLiveData<String> getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName.setValue(userName);
}
public LiveData<String> getUid() {
return uId;
}
public void setUid(String input) {
uId.setValue(input);
}
public MutableLiveData<String> getChatRef() {
return chatRef;
}
public void setChatRef(String chatRef) {
this.chatRef.setValue(chatRef);
}
}
这是我的 SubFragmentPagerAdapter,它是最内部 ViewPager 的适配器(使用 getChildFragmentManager() 的适配器)
需要提到的一件重要的事情是,这是 TabLayout 下面的 viewPager,但是 TabLayout 的 Fragment 有一个父级,它是另一个 ViewPager 并且具有相同的配置....FragmentPagerAdapter、“BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT”和在构造函数中初始化的 Fragments ,你可以看到没有notifyDatasetChanged(),因为我通过LiveData回调管理所有信息:
public class MySubFragmentPagerAdapter extends FragmentPagerAdapter {
private ChatFragment mChatFragment;
private SessionsFragment mSessionsFragment;
public MySubFragmentPagerAdapter(@NonNull FragmentManager fm,
FlyHighUser flyHighUser,
MyPagerController.FragmentPager fragmentPagerController) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mChatFragment = ChatFragment.newInstance(flyHighUser);
mSessionsFragment = new SessionsFragment();
/*This is a listener I made that allows the Fragments to be able to change the pages of their parent viewPgaer.*/
mSessionsFragment.setSessionFragmentInterface(fragmentPagerController);
}
private static final int NUMBER_OF_FRAGMENTS = 2;
@NonNull
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return mSessionsFragment;
case 1:
return mChatFragment;
}
return null;
}
@Override
public int getCount() {
return NUMBER_OF_FRAGMENTS;
}
}
完整的流程应该是这样的:
MainActivity(Nav)/MainFrag(viewPager)/Frag(at 0)
@Override
public void onItemClick(String uID, String userName) {
/*Set the values that Fragment at position 1 should solve, this include connecting the FireBase Listener with the uid, and getting the userName String*/
mSharedViewModel.setUid(uID);
mSharedViewModel.setUserName(userName);
/* this changes the page to position 1*/
fragmentPagerController.scrollToFragment(1);
}
当页面更改为1时,必须同时发生两件事,必须添加一个选项卡,并且SessionsFragment(在初始化时创建)必须向给定的引用添加一个Firebase监听器
MainActivity(Nav)/MainFrag(viewPager)/Frag(at 1)(subViewPgaer + TabLayout)。
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSharedViewModel = ViewModelProviders.of(mContextWeakReference.get()).get(SharedViewModel.class);
mSharedViewModel.getUserName().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
/*The Tab is added but not drawn*/
mTabLayout.addTab(mTabLayout.newTab().setText(s));
}
});
mSharedViewModel.getSessionTitle().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
/* The Tab is added but not drawn*/
mTabLayout.addTab(mTabLayout.newTab().setText(s));
}
});
}
MainActivity(Nav)/MainFrag(viewPager)/Frag(at 1)(subViewPgaer + TabLayout)/Frag(at 0) <- 又名:SessionsFragment
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSharedViewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
mSharedViewModel.getUid().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
uid = s;
/*this works perfectly fine, I wanted the Firebase data to be bound by the MainActivity LifeCycle.
Observer is added only once, and there is only one Firebase Listener at any given moment (italian chef kiss) BTW observeUserSessions() is a LiveData setter for the observer, lifeCycleOwner and Firebase reference*/
mContextWeakReference.get().observeUserSessions(mObserver, "sessions/" + s);
}
});
mSharedViewModel.getUserName().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(String s) {
clientName = s;
/*this is viewDataBinding*/
binding.setClientName(clientName);
}
});
}
没有错误消息,选项卡已添加但未显示。
最佳答案
这并不是一个真正的答案,但我想发生这种情况的原因与我们在另一个 Viewpager 中使用 ViewPager 时需要使用 getChildFragmentManager() 的原因相同。
也许因为生命周期是如此分层,因此没有机会在初始化过程之外绘制选项卡,也许片段的容器无法找到可以附加自己的东西,这可能是充气机?,容器?我真的对 Android 架构一无所知,如果我愿意的话我就不会遇到这个问题了。
问题是 Tablayout.Tab 没有从其父级获取所需正确 View 的选项,或者问题可能直接依赖于 TabLayout 本身,而没有安装正确 FragmentManager 的选项。或者也许有但我还没有找到它,我认为这是主要问题。
无论如何,我完全理解这个问题是否故意存在问题,毕竟我承认 android.os 的小部件和组件提供的一些工具确实足以构建完全自定义的东西请记住,只要对它们的使用的了解会扩展,并且它们的行为将在与环境无关的情况下保持不变,问题是幕后发生了太多事情,知道如何使用它们,只意味着知道如何按照它们应该使用的方式使用它们,这实际上意味着一个人一无所知……而且我个人认为,这对那些花了多年时间掌握这些知识的人来说是不公平的系统,如果对 Android 架构组件和小部件有肤浅了解的人可以构建出同等水平的东西。
关于java - addTab() 在回调中不添加任何 TabLayout.Tab,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58675186/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!