2

The app I'm building has a use case in which, based on some data I create sections in a Fragment. To visualize, a given fragment A has a layout with main container element being ScrollView. There, the scroll view has a toolbar (irrelevant for this question) and then ConstraintLayout (showing all the fragment's content, lets call it masterLayout). What I need to be able to do is to, based on a boolean (let's call it hasSection) remove a view component from masterLayout. Therefore, sometimes fragment A will show masterLayout (which is NOT at position 0 in the container - it is 5th component in the view tree) and sometimes it will not. Now, I tried to simply calling:

((ViewGroup)masterLayout.getParent()).removeView(masterLayout);

which works partially. The problem here is, the view is removed, but the space it occupied is not. Therefore, any other children appearing after that view in the view tree will not be "moved up". I can't leave it like that, as the masterLayout has height = 200dp. As you can see, it will occupy a significant portion of the screen. Therefore, after researching the web, I found the solution to set its visibility:

masterLayout.setVisibility(View.GONE);

which works as intended. The view is removed, all further child views are moved up accordingly so there is no empty and unwanted space. The problem is that when I do transition away from that fragment (lets say there is a clickable view which takes the user to a different fragment) and come back to it again (for example using back button with onBackPressed()), masterLayout that has been set to visibility = View.GONE will not show up anymore.

How can I achieve the functionality of removing/hiding a particular view from a layout, with having the next views beneath it moved up to cover empty space (like View.GONE does) while restoring the original layout when navigating back to described fragment?

Full code of the logic:

if(isTypeA){
        new FetchUser(USERID){
            @Override
            protected void onPostExecute(User user){
                mUser = user;
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

        new FetchImages(mUser.getType()){
            @Override
            protected void onPostExecute(List<Image> result){
                if(mImageList.isEmpty() && !result.isEmpty()){
                    mImageList.addAll(result);
                    mAdapter = new ItemAdapter(getChildFragmentManager(), mImageList.size(), mImageList);
                    mItemCardPager.setAdapter(mAdapter);
                }else{
                    if(mMasterLayout != null){
                        mMasterLayout.setVisibility(View.GONE);
                    }
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Austie
  • 67
  • 7

1 Answers1

1

The Fragment lifecycle can help here.

One approach would be to always restore that masterLayout to visibility View.VISIBLE in the fragment's onResume method.

@Override
public void onResume() {
    super.onResume();
    masterLayout.setVisibility(View.VISIBLE);
}
albert c braun
  • 2,650
  • 1
  • 22
  • 32
  • It does not work unfortunately, when setting previously its visibility to View.GONE. I had tried your approach before. – Austie Jun 30 '17 at 14:06
  • Interesting. Ok. I guess it would be helpful to see the code your app is using, especially the code for that fragment and the code that adds or replaces that fragment when the app displays the next fragment. – albert c braun Jun 30 '17 at 14:38
  • The fragment A I'm talking about serves the purpose of user profile view. Therefore there is a header section with image + some other info, below that there is a section with viewpager that holds images displayed as card views. Below that section there is other type of content, but in a similar manner. The thing is, the user can have two types, lets say typeA and typeB. If user is of typeA, then when profile is shown, second section (with the viewpager) should be shown. If he is of typeB, then viewpager section should not be there, and content below should be displayed right under header – Austie Jun 30 '17 at 14:53
  • The code here is pretty basic (I think). Fragment is created by passing in the boolean that indicates the type. Based on the boolean, async task is executed that fetches the list of images (for the card views in viewpager). If list is empty > remove that view from the layout (by calling the masterLayout.setVisibility(View.GONE), else instantiate adapter and set it to viewpager. Everything here works, but setting masterLayout.setVisibility(View.VISIBLE) in onResume() does not restore this view .... – Austie Jun 30 '17 at 14:58
  • It's difficult for me to find a possible solution without the actual code, I'm afraid. Even with the code it's difficult. :-) I can offer a wild guess. I wonder if it would help to move the code that populates the ViewPager's adapter and sets the adapter onto the ViewPager into onResume. – albert c braun Jun 30 '17 at 15:34
  • I've added the code in the original post. The logic is that if the user is of typeA, then get the list of images (as user of typeA should display the images in the viewpager I talked about). If however the list fetched returns 0 items, then I would like to remove the masterLayout (the view that holds the viewpager populated by cardView images). If the user is of typeB, then of course the layout should be removed as well. Calling setVisibility(View.VISIBLE) in onResume() does nothing though and removeView() leaves empty space in layout ... – Austie Jun 30 '17 at 16:00
  • Another wild guess: does calling invalidate() on masterLayout help? – albert c braun Jun 30 '17 at 16:00
  • I tried to requestLayout() and invalidate(). I tried wrapping it in a ViewStub and then invalidatiing > it did not work. I tried to inflate the whole layout all over again in onResume, just to see if it would work. It did not :( – Austie Jun 30 '17 at 16:02
  • i'm sorry - another guess: maybe mAdapter.notifyDataSetChanged() is useful? – albert c braun Jun 30 '17 at 16:57
  • I forgot to reply over all that time. Your solution, with setting the visibility to View.Visible finally worked. Turned out that the problem was elsewhere, which was my fault. I will accept your solution as correct, thanks for the help :) – Austie Aug 07 '17 at 08:21