Change layout while orientation change at runtime in a fragment without recreating the view

前端 未结 2 542
借酒劲吻你
借酒劲吻你 2021-01-02 18:53

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

2条回答
  •  旧巷少年郎
    2021-01-02 19:21

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

    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:

    
    
    
    

    Then some private member variables:

    private GridView mGridViewPortrait;
    private GridView mGridViewLandscape;
    

    Then in 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);
                }
            }
    

    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.

    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. 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)).

    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.

    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.

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

    Some side notes in your code:

    • 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

    I wish you good luck!

提交回复
热议问题