纵向上的 Viewpager 和横向上的两个窗格

问题描述 投票:0回答:4

我正在尝试实现一种布局,当设备纵向显示时显示视图寻呼机,而当设备横向显示时显示两个窗格。

所以我制作了两个不同的布局文件,一个只有一个ViewPager,另一个有一个LinearLayout,另一个有两个FrameLayout,我认为没有必要在这里展示它们。这两种配置还有一个布尔值

hasTwoPanes

@Inject FragmentOne fragmentOne;
@Inject FragmentTwo fragmentTwo;

@Override
protected void onCreate(Bundle state) {
    super.onCreate(state);
    setContentView(R.layout.activity_main);

    FragmentManager fm = getSupportFragmentManager();
    boolean hasTwoPanes = getResources().getBoolean(R.bool.hasTwoPanes);

    TabLayout tabLayout = findViewById(R.id.tab_layout);
    ViewPager viewPager = findViewById(R.id.view_pager);
    if (hasTwoPanes) {
        tabLayout.setVisibility(View.GONE);
    } else {
        tabLayout.setVisibility(View.VISIBLE);
        tabLayout.setupWithViewPager(viewPager);
        viewPager.setAdapter(new MyPagerAdapter(fm));
    }

    FragmentOne frag1 = (FragmentOne) fm.findFragmentByTag(getFragmentName(0));
    if (frag1 != null) fragmentOne = frag1;

    FragmentTwo frag2 = (FragmentTwo) fm.findFragmentByTag(getFragmentName(1));
    if (frag2 != null) fragmentTwo = frag2;

    if (hasTwoPanes) {
        if (frag1 != null) {
            fm.beginTransaction().remove(fragmentOne).commit();
            fm.beginTransaction().remove(fragmentTwo).commit();
            fm.executePendingTransactions();
        }

        fm.beginTransaction().add(R.id.frame_frag1, fragmentOne, getFragmentName(0)).commit();
        fm.beginTransaction().add(R.id.frame_frag2, fragmentTwo, getFragmentName(1)).commit();
    }
}

private class MyPagerAdapter extends FragmentPagerAdapter {

    MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        if (position == 0) {
            return fragmentOne;
        } else {
            return fragmentTwo;
        }
    }

    @Override
    public int getCount() {
        return 2;
    }

}

private static String getFragmentName(int pos) {
    return "android:switcher:" + R.id.view_pager + ":" + pos;
}

两个片段被注入了 Dagger。如果不存在任何片段,这些注入的片段将根据方向添加到视图分页器或布局中。

因为视图寻呼机适配器为其片段提供了名称,所以我需要知道该名称(因此使用

getFragmentName(int pos)
方法)才能在旋转后取回该片段。

结果是,当从纵向旋转到横向时,状态可以正确恢复,但是当从横向旋转到纵向时,视图寻呼机完全为空。当我旋转回横向时,碎片重新出现。选项卡布局也有问题,没有滑动动画,我只能连续从一个选项卡滑动到另一个选项卡,在任何地方停止。

澄清一下,这是在 Activity 中发生的,没有父片段。即使未显示片段,也会调用片段的

onViewCreated
。视图分页器似乎正确恢复了
instantiateItem
中的片段引用。此外,在调试时,片段的
added
为 true,
hidden
为 false。这看起来像是一个视图寻呼机渲染问题。

  • 如何让视图寻呼机显示我的片段?
  • 有更好的方法来实现我想要的行为吗?
android android-fragments android-viewpager android-configchanges
4个回答
3
投票

您是否尝试过使用 PagerAdapter 而不是 FragmentPagerAdapter?您将更好地控制片段的创建和处理。否则你不知道 FragmentPagerAdapter 在做什么(他为你做这件事,但可能是错的)。

您可以将大部分逻辑移至该类中,从而使活动更加清晰,并且可能还可以解决您遇到的问题。

编辑:由于我们在这里讨论方向变化,您可能应该合并

onConfigurationChanged
回调来更好地处理该逻辑。


3
投票

我找到的解决方案非常简单,在我的寻呼机适配器中覆盖

getPageWidth
,如下所示:

@Override
public float getPageWidth(int position) {
    boolean hasTwoPanes = getResources().getBoolean(R.bool.hasTwoPanes);
    return hasTwoPanes ? 0.5f : 1.0f;
}

R.bool.hasTwoPanes
是默认配置中可用的布尔资源,并且
values-land
。我的布局对于两种配置都是相同的,并且选项卡布局只是隐藏在横向上。

片段恢复由视图寻呼机自动完成。


2
投票

试试这个

肖像XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tab"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

景观 Xml:

 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <FrameLayout
        android:id="@+id/fragmentA"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />
    <FrameLayout
        android:id="@+id/fragmentB"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />
</LinearLayout>

Java 活动:

package com.dev4solutions.myapplication;

import android.graphics.Point;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

import com.dev4solutions.myapplication.fragment.FragmentA;
import com.dev4solutions.myapplication.fragment.FragmentB;

public class FragmentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Point point = new Point();
        getWindowManager().getDefaultDisplay().getSize(point);
        setContentView(R.layout.activity_frag);
        if (point.y > point.x) {
            TabLayout tabLayout = findViewById(R.id.tab);
            ViewPager viewPager = findViewById(R.id.pager);
            tabLayout.setupWithViewPager(viewPager);
            viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager()));

        } else {
            getSupportFragmentManager()
                    .beginTransaction()
                    .add(R.id.fragmentA, new FragmentA())
                    .commit();
            getSupportFragmentManager()
                    .beginTransaction()
                    .add(R.id.fragmentB, new FragmentB())
                    .commit();
        }
    }
}

0
投票

ViewPager2 纵向和横向模式的配置更改处理

如果您在配置更改期间遇到

ViewPager2
问题,尤其是在纵向和横向模式之间转换时,您可以实施以下解决方案。

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Check if the orientation has changed to landscape or portrait
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE || newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {

        // Save the current index for later use
        int currentIndex = index;

        // Set the ViewPager to the previous item, but not below the first item
        viewPager2.setCurrentItem(Math.max(index - 1, 0), false);

        // Reset the ViewPager to the original item to maintain the user's current position
        viewPager2.setCurrentItem(currentIndex, false);
    }
}

确保您已在清单文件中添加此行:

android:configChanges="orientation|screenSize"

<activity
    android:name=".ui.activity.MainActivity"
    android:configChanges="orientation|screenSize"
    android:exported="false" />
© www.soinside.com 2019 - 2024. All rights reserved.