Android Fragments中方向改变时布局的更改

6

请提供一个解决方案。

当我旋转我的片段时,它应该变成横向模式并显示另一个布局。但屏幕没有旋转到横向。

我的代码如下:

 <activity
        android:name=".activites.MainActivity"
        android:launchMode="singleInstance"
        android:configChanges="keyboardHidden|screenLayout|screenSize|orientation"
        />

这是主要布局,称为仪表板,现在处于竖屏模式:

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     View  view=View.inflate(getContext(), R.frag_dashboard,null);
     changeview= (ShimmerTextView)view.findViewById(R.id.changeview); 
     return view;
}

当我旋转屏幕时,该片段将切换到横向模式并设置另一种布局,其中"prayer_times"是新的布局。
   @Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(getContext(), "landscape", Toast.LENGTH_SHORT).show();
        view=View.inflate(getContext(), R.layout.prayer_times,null);

    }
}

我创建了 prayer_times 的 layout_land 布局。


抱歉,它对我来说无法工作。 - AndroidSRS
@AndroidSRS 最好使用不同的文件夹来存放相同布局名称的竖屏和横屏布局文件。 - Soham
我已经得到答案了,我使用了 "getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);" 现在它可以工作了。 - AndroidSRS
但是有一个问题,布局不会根据方向的改变而改变。 - AndroidSRS
7个回答

15

如果您的片段在方向更改时没有重新加载的问题,您可以直接重新加载。

layoutlayout-land文件夹中添加两个具有相同名称的布局。

这将显示正确定向的布局,以便在设备旋转时更改布局,请在片段本身的onConfigarationChanged方法中添加以下内容。

@Override
public void onConfigurationChanged(Configuration newConfig){
    super.onConfigurationChanged(newConfig);
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE || newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        try {
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            if (Build.VERSION.SDK_INT >= 26) {
             ft.setReorderingAllowed(false);
            }
            ft.detach(this).attach(this).commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1
谢谢。我试图将它放在我的基础片段类中,但它没有起作用(片段会从屏幕上消失)。一旦我将其移动到最终的片段子类中,它就开始工作了。 - tmm1
1
谢谢,这很有帮助,它节省了我整整一天的时间。 - Mehul Tank
1
对我来说完美地工作了! - GetSwifty
捕获通用异常不是一个好主意。https://source.android.com/setup/contribute/code-style#dont-catch-generic-exception - alizeyn
@AliZeynali 1. 因为onConfigurationChanged不仅在方向改变时调用,例如“keyboardHidden”,因此此操作仅在方向更改为纵向或横向时执行。 - UdayaLakmal
显示剩余2条评论

3

如果旋转屏幕时调用了onCreateView函数,您可以在其中执行以下操作:

if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE) {
    ......
} else if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT) {
    .........
}

从这个角度来看,竖屏模式可以正常工作,但横屏模式无法正常工作。 - AndroidSRS

3

虽然晚了,但这会帮助某些人。

在 V4 Fragment 中尝试以下操作:

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

        if (getFragmentManager() != null) {
            getFragmentManager()
                    .beginTransaction()
                    .detach(this)
                    .attach(this)
                    .commit();
        }
    }

1
你想做的事情相当复杂。Android Fragments 不应该被旋转。 我有同样的问题,并找到了解决方案。在我的情况下,我想呈现一个包含不同菜单页面的 Fragment,这些页面将根据方向进行旋转。
只需创建一个作为基础的 Fragment,并包含一个简单的 LinearLayout(或任何其他布局类型)。这个 LinearLayout 将用作我们菜单的画布:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llMenuCanvas"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</LinearLayout>

接下来,我们希望将基础项片段编码为一个抽象类,由所有菜单项片段实现:
public abstract class NavMenuItem extends Fragment {

    static final String TAG = "yourTag"; // Debug tag

    LinearLayout canvas;
    View hView; // we'll keep the reference of both views
    View vView;

    // All we'll need to do is set these up on our fragments
    abstract int getVerticalLayoutResource();
    abstract int getHorizontalLayoutResource();
    abstract void setupUI(); // assigns all UI elements and listeners

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.menu_base, container, false); // sets up the layout for this fragment

        // keeping our references to both layout versions
        hView = inflater.inflate(getHorizontalLayoutResource(), container, false);
        vView = inflater.inflate(getVerticalLayoutResource(), container, false);

        canvas = view.findViewById(R.id.llMenuCanvas); // this is the magic part: Our reference to the menu canvas

        // returning our first view depending on orientation
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
            canvas.addView(hView);
        }else{
            canvas.addView(vView);
        }
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setupUI(); // here we set up our listeners for the first time
    }

    // Here we update the layout when we rotate the device
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        canvas.removeAllViews();

        // Checking screen orientation
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            canvas.addView(hView);
        }
        else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            canvas.addView(vView);
        }
        setupUI(); // we always need to rebind our buttons

    }

}

这是一个菜单项片段的示例,根据设备的方向进行旋转。
public class NavMenuMain extends NavMenuItem{

    static final String TAG = "yourTag"; // Debug tag

    // Your layout references, as usual
    ImageButton btnCloseMenu;

    // here we set up the layout resources for this fragment
    @Override
    int getVerticalLayoutResource() { // vertical layout version
        return R.layout.menu_main_port;
    }

    @Override
    int getHorizontalLayoutResource() { // horizontal layout version
        return R.layout.menu_main_land;
    }

    @Override
    void setupUI(){

        // Setup button listeners and layout interaction here

        // REMEMBER: the names of your layout elements must match, both for landscape and portrait layouts. Ex: the "close menu" button must have the same id name in both layout versions

    }

}

希望它有所帮助。

0
你所需要做的就是在你的res文件夹内新建一个名为layout-land的文件夹,并将与你的片段布局同名的xml文件放入其中,框架会在方向改变时查找该.xml文件。请点击这里了解更多详情。

是的,我按照你说的做了。但是没有任何改变。 - AndroidSRS
onConfigurationChanged函数没有被调用。 - AndroidSRS
你是在使用模拟设备还是真实设备? - Nir Duan

0

0
当你更改方向时,你的片段会被销毁并重新创建(参见此处以获得更好的理解)。因此,在onConfigurationChanged中,您需要填充新布局,但是这是无用的,因为当您的片段重新创建时,onCreateView将再次调用; 换句话说,您的旧布局将再次填充。因此,最好以这种方式处理:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View  view;

    if(getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {

        view = View.inflate(getContext(), R.frag_dashboard,null);
        changeview = (ShimmerTextView)view.findViewById(R.id.changeview);
    } else(getActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {

        Toast.makeText(getContext(), "landscape", Toast.LENGTH_SHORT).show();
        view = View.inflate(getContext(), R.layout.prayer_times,null);
    }

    return view;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接