更改布局而改变方向在运行时的一个片段,而无须重新创建视图 [英] Change layout while orientation change at runtime in a fragment without recreating the view

查看:110
本文介绍了更改布局而改变方向在运行时的一个片段,而无须重新创建视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试开发第一个应用程序,从网上下载图像,并显示在一个GridView。在GridView是主要活动的一个片段。下载过程是用在OnCreate函数的AsyncTask的。为了不再次下载图像,同时改变方向,我设置了安卓configChanges =方向|屏幕尺寸在Android清单。然后OnCreate函数只调用一次,一切都很好......除了我不得不做出的布局做一些更改,在横向模式下的gridview的片段。所以我创建2布局页: fragment_library.xml fragment_library_land.xml 布局/文件夹。为了使这些变化的工作,我trye​​d使用onConfigurationChanged功能手动更改库片段的布局。在运行时,程序评估功能,并通过在正确的情形(纵向或横向),但使用的布局仍然是一个用于人像模式: fragment_library.xml ...

I try to develop a first app that download images from the net and show them in a gridview. The gridview is a fragment of a main Activity. The download process is made with an AsyncTask in the onCreate Function. In order not to download again the images while changing orientation, i set the android:configChanges="orientation|screenSize" in the Android Manifest. Then the onCreate function is only call once and everything's good ... except that i've got to make a few changes in the layout for the gridview fragment in landscape mode. So i created 2 layout sheets : fragment_library.xml and fragment_library_land.xml in the layout/ folder. To make these changes work, i tryed to change the layout of the library fragment manually by using the onConfigurationChanged function. At runtime, the program evaluate the function and pass in the good case (portrait or landscape) but the layout used is still the one for portrait mode : 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

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

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"
/>

感谢您的帮助:)

Thanks for help :)

推荐答案

这是不可能的。片段可以不更新它的布局动态。您确实有一些其他的选择。

It is not possible. A Fragment cannot update it's layout dynamically. You do have some other options however.

1 的。这不是一个球迷,但你可能有一个片段的布局,无论是人像,并在同一时间的水平的观点和显示和隐藏。

1. Not a fan of this, but you may have a Fragment's layout with both the portrait and the horizontal views at the same time and show and hide.

fragment_library.xml:

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"
/>

然后一些私有成员变量:

Then some private member variables:

private GridView mGridViewPortrait;
private GridView mGridViewLandscape;

然后在 onConfigurationChanged(配置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);
            }
        }

的几点:请注意,我离开了code指的两个GridView。我也改变了你的GridView给私人,并更名为mGridView *。私人保持它的数据包封和m,因为它是类的一个成员,只是约定。我也改变了的if-else子句,因为我想要的画像检查来第一次。

Some points: Note that i left out the code to refer the both GridViews. I also changed your GridView to private and also changed the name to mGridView*. Private to keep it "data-encapsulated" and "m" because it is a member of the class, just convention. I also changed the if-else clause because I wanted the portrait check to come first.

这方法是最快的,最简单的,但它有可能成为沉重的系统,如果你有大的布局,所以做的不可以使用这个,如果你有很多的东西。 preferably不要使用此方法在所有。

This way is the fastest and easiest, however it might become heavy for the system if you have big layouts so do not use this if you have many things. Preferably do not use this approach at all.

2 的。正确的方法是让Andorid的照顾和取向也移动你的XML到一个合适的目录。然而,这将重新创建片段(如果您没有设置 setRetainInstance(真); ,你不会在这​​种情况下,这将使片段无法重新创建它的布局(实际上是寻找了<一href="http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance%28boolean%29">the保留方法它没有提到 onCreateView ,所以你可以尝试设置为true藏汉试))。

2. The proper way is to let the Andorid take care of the orientation and also move your XML to a right directory. This however will recreate your Fragment (if you do not set setRetainInstance(true); which you will not in this case; this will make the Fragment not recreate it's layout (actually looking up the retain method it does not mention onCreateView so you may try to set this to true aswell and try)).

将您fragment_library_land.xml的目录布局,土地,而不是布局并将其命名为 fragment_library 的.xml。注大胆,将具有相同的名称,但留在不同的目录中。这样,机器人就会知道,并根据方向右侧的布局。

Move your fragment_library_land.xml to the directory layout-land instead of layout and name it fragment_library.xml. Note the bold, it will have the same name but stay in different directories. This way Android will know and take the right layout based on the orientation.

如果我明白你为什么会不想重新创建片段,因为的onCreate(包savedInstanceState)将会再次调用(与 setRetainInstance(真); 也不会和为考虑到我刚才写的,你可以试试看),从而创建 GetLibraryTask 和下载的新实例再次图像。这可能是,如果你使用一个数据库来存储图像prevented,如果你有这样的保留曲目,如果你已经下载的图像或不是一个布尔值。在 GetLibraryTask 然后你将挑选出这是没有下载的图像,无论是第一次运行任务,或者如果方向改变。您还需要放在一个停止检查库中的任务,在下载循环,每个项目检查之前,如果你都应该下载图片或者片段不再可用,因此退出任务。

If I have understood why you will not want to recreate the Fragment because onCreate(Bundle savedInstanceState) will be called again (with setRetainInstance(true); it will not and to as regard to what I wrote earlier you may give it a try) thus creating a new instance of GetLibraryTask and download the images again. This could be prevented if you used a database to store the images and if you had a boolean value that kept track if you had downloaded the image or not. In GetLibraryTask you would then pick out the images which are not downloaded, be it the first time the task is run or if the orientation changed. You would also require to put in a stop check in the library task in the download loop that before each item checks if you are supposed to download the image or if the fragment is no longer available and thus quit the task.

现在,当你改变方向的活动将重新LibraryFragment并根据定向无论是布局或布局的土地将被使用。

Now when you change orientation the Activity will recreate the LibraryFragment and depending on the orientation either layout or layout-land will be used.

一些旁注在code:

  • 正如我之前写的,千万不要用公共访问,一定要使用专用的或必要的保护时。私人可以用所有的时间,但并有getter和setter(accesors和修改器)来进行通信。
  • 使用M为preFIX的成员变量,在这种情况下,公开的GridView GridView控件私人GridView的mGridView 私人布尔isImageAdapterPopulated 私人布尔mIsImageAdapterPopulated
  • 不要使用类基本类型,如果你不需要它。您可能需要在不支持原始类型或类固定等列表。
  • onConfigurationChanged(配置NEWCONFIG)你膨胀的XML,它返回一个视图,但是你没有做任何事的
  • As I wrote earlier, never use public access, always use private or protected when necessary. Private can be used all time though and have getters and setters (accesors and mutators) to do the communication.
  • Use "m" as a prefix on member variables, in this case public GridView gridview would be private GridView mGridView and private Boolean isImageAdapterPopulated would be private boolean mIsImageAdapterPopulated
  • Never use classes for primitive types if you do not need it. You may need it in lists which does not support primitive types or class retention etc.
  • In your onConfigurationChanged(Configuration newConfig) you inflate an XML and it returns a View but you are not doing anything with it

我祝你好运!

这篇关于更改布局而改变方向在运行时的一个片段,而无须重新创建视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆