在片段中在运行时更改方向而不重新创建视图时更改布局

时间:2013-01-15 13:52:59

标签: android layout runtime orientation fragment

我尝试开发第一个从网上下载图像的应用程序,并在gridview中显示它们。 gridview是主Activity的片段。下载过程是使用onCreate函数中的AsyncTask完成的。为了在更改方向时不再下载图像,我在Android Manifest中设置了android:configChanges="orientation|screenSize"。然后onCreate函数只调用一次,一切都很好......除了我必须在横向模式下对gridview片段的布局进行一些更改。所以我在布局/文件夹中创建了2个布局表:fragment_library.xmlfragment_library_land.xml。为了使这些更改起作用,我尝试使用onConfigurationChanged函数手动更改库片段的布局。在运行时,程序会评估函数并传递好的大小写(纵向或横向),但使用的布局仍然是纵向模式:fragment_library.xml ...

public class LibraryFragment extends Fragment {
    public GridView gridview;
    private Boolean isImageAdapterPopulated = false;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        GetLibraryTask getLibraryTask = new GetLibraryTask(this);
        getLibraryTask.execute(Config.URL + "action=getLibrary");
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        if (container == null)
            return null;

        // gridview
        View V = inflater.inflate(R.layout.fragment_library, container, false);
        gridview = (GridView)V.findViewById(R.id.gridview);

        if(this.isImageAdapterPopulated)
            this.setGridAdapter();
        return V;
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig){
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
            inflater.inflate(R.layout.fragment_library_land, null);
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
            inflater.inflate(R.layout.fragment_library, null);
        }
    }

    public void setGridAdapter(){
        this.isImageAdapterPopulated = true;
        gridview.setAdapter(new ImageAdapter(getActivity()));
    }

    // ...
}

fragment_library.xml

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/gridview"
    android:cacheColorHint="@android:color/transparent"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:columnWidth="200dp"
    android:numColumns="auto_fit"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="20dp"
    android:stretchMode="columnWidth"
    android:gravity="bottom"
/>

fragment_library_land.xml

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/gridview"
    android:cacheColorHint="@android:color/transparent"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:columnWidth="400dp"
    android:numColumns="2"
    android:verticalSpacing="50dp"
    android:horizontalSpacing="50dp"
    android:stretchMode="columnWidth"
    android:gravity="bottom"
/>

感谢您的帮助:)

2 个答案:

答案 0 :(得分:16)

这是不可能的。片段无法动态更新其布局。但是你确实有其他选择。

1 。不是这个的粉丝,但你可能同时拥有Fragment的布局同时包含肖像和水平视图并显示和隐藏。

fragment_library.xml:

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/gridview_portrait"
    android:cacheColorHint="@android:color/transparent"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:columnWidth="200dp"
    android:numColumns="auto_fit"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="20dp"
    android:stretchMode="columnWidth"
    android:gravity="bottom"
/>
<GridView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/gridview_landscape"
    android:cacheColorHint="@android:color/transparent"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:columnWidth="400dp"
    android:numColumns="2"
    android:verticalSpacing="50dp"
    android:horizontalSpacing="50dp"
    android:stretchMode="columnWidth"
    android:gravity="bottom"
    android:visible="gone"
/>

然后是一些私有成员变量:

private GridView mGridViewPortrait;
private GridView mGridViewLandscape;

然后在onConfigurationChanged(Configuration newConfig)

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

            if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
                 mGridViewPortrait.setVisibility(View.VISIBLE);
                 mGridViewLandscape.setVisibility(View.GONE);
            }

            else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
                 mGridViewPortrait.setVisibility(View.GONE);
                 mGridViewLandscape.setVisibility(View.VISIBLE);
            }
        }

有些观点:请注意,我省略了代码以引用两个GridView。我还将GridView更改为private,并将名称更改为mGridView *。私有以保持“数据封装”和“m”,因为它是类的成员,只是约定。我也改变了if-else子句,因为我想先将肖像检查放在第一位。

这种方式是最快最简单的方法,但是如果你有大布局,它可能会变得很重,所以如果你有很多东西,使用它。最好不要使用这种方法。

2 。正确的方法是让Andorid处理方向,并将XML移动到正确的目录。然而,这将重新创建您的片段(如果您没有设置setRetainInstance(true);,在这种情况下您将不会;这将使片段不重新创建它的布局(实际上查找the retain method它没有提到{{1所以你可以尝试将其设置为true,并尝试))。

将fragment_library_land.xml移动到目录layout-land而不是layout,并将其命名为 fragment_library .xml。注意粗体,它将具有相同的名称,但保留在不同的目录中。这样Android就会根据方向知道并采用正确的布局。

如果我已经明白为什么你不想重新创建片段,因为onCreateView将再次被调用(onCreate(Bundle savedInstanceState)它将不会,并且就我之前写的内容而言,你可以给它一个尝试)因此创建setRetainInstance(true);的新实例并再次下载图像。如果您使用数据库存储图像,并且如果您有一个布尔值,如果您已下载图像,则可以防止这种情况。在GetLibraryTask中,您将选择未下载的图像,无论是第一次运行任务还是更改方向。您还需要在下载循环中的库任务中进行停止检查,在每个项目检查之前是否应该下载图像,或者片段是否不再可用,从而退出任务。

现在,当您更改方向时,Activity将重新创建LibraryFragment,并根据方向使用layout或layout-land。

代码中的一些附注:

  • 正如我之前所写,永远不要使用公共访问,必要时始终使用私有或受保护。 Private可以一直使用,并且有getter和setter(加法器和mutators)来进行通信。
  • 使用“m”作为成员变量的前缀,在这种情况下,GetLibraryTask将是public GridView gridviewprivate GridView mGridView将是private Boolean isImageAdapterPopulated
  • 如果您不需要类,则不要使用基类类。您可能需要在不支持基本类型或类保留等的列表中使用它。
  • 在您的private boolean mIsImageAdapterPopulated中,您为XML充气并返回一个视图,但您没有对其进行任何操作

祝你好运!

答案 1 :(得分:0)

您可以使用oncongi更改方法。 请参阅此链接Change Fragment layout on orientation change