0

I'm trying to adapt my app to the Adaptative UI Flows example, but I'm missing something and I don't know what it is. As you'll see below, the NewsListFragment loads its layout depending on whether the device is in portrait or landscape mode, and since I'm not handling manually configuration changes, going from portrait to landscape changes such layout.

Expected behaviour: When the layout is portrait, show only the list. When the layout is landscape, show both the list and the webview.

Actual behaviour: When the layout is portrait, only the list is shown. BUT, when the layout is landscape, the NewsListFragment disappears, which does not seem to make any sense since I've set a fixed width for it and its height is set to match_parent.

NewsListFragment:

public class NewsListFragment extends ListFragment implements OnRefreshListener {

private static PullToRefreshLayout mPullToRefreshLayout;
private NewsFragmentArrayAdapter listAdapter;
private NewsFeedProvider newsFeedProvider;
private NewsListFragmentListener mCallback;

/**
 * Called to do initial creation of a fragment.  This is called after
 * {@link #onAttach(android.app.Activity)} and before
 * {@link #onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)}.
 * <p/>
 * <p>Note that this can be called while the fragment's activity is
 * still in the process of being created.  As such, you can not rely
 * on things like the activity's content view hierarchy being initialized
 * at this point.  If you want to do work once the activity itself is
 * created, see {@link #onActivityCreated(android.os.Bundle)}.
 *
 * @param savedInstanceState If the fragment is being re-created from
 *                           a previous saved state, this is the state.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (listAdapter == null) {
        listAdapter = new NewsFragmentArrayAdapter(getActivity());
        setListAdapter(listAdapter);
    }
    if (newsFeedProvider == null) {
        newsFeedProvider = new NewsFeedProvider(getActivity());
    }
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    getListView().setItemChecked(position, Boolean.TRUE);
    mCallback.onNewsArticleSelected(position);
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    try {
        mCallback = (NewsListFragmentListener) activity;
    }
    catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement NewsListFragmentListener");
    }

    ((NewsReaderActivity) activity).onSectionAttached(
            new ArrayList<>(
                    Arrays.asList(
                            Utils.getStringArray(
                                    getActivity().getApplicationContext(),
                                    "navigation_drawer_items", new String[]{""})
                    )
            ).indexOf(Utils.getString(getActivity().getApplicationContext(), "title_section1",
                    "Home"))
    );
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View ret = inflater.inflate(R.layout.fragment_news_feed, container, false);

    listAdapter.updateShownNews();

    return ret;
}

/**
 * Attach to list view once the view hierarchy has been created.
 *
 * @param view
 * @param savedInstanceState
 */
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    // This is the View which is created by ListFragment
    ViewGroup viewGroup = (ViewGroup) view;

    // We need to create a PullToRefreshLayout manually
    mPullToRefreshLayout = new PullToRefreshLayout(viewGroup.getContext());

    Options.Builder optionsBuilder = Options.create();

    int retrieved = Utils.getInt(getActivity(), "feed_refresh_distance_percentage",
            R.integer.feed_refresh_distance_percentage);
    float scrollDistance = (float) retrieved / 100;
    optionsBuilder = optionsBuilder
            .scrollDistance(scrollDistance);

    optionsBuilder = optionsBuilder.headerTransformer(new TranslatableHeaderTransformer());

    // We can now setup the PullToRefreshLayout
    ActionBarPullToRefresh.from(getActivity())

            // We need to insert the PullToRefreshLayout into the Fragment's ViewGroup
            .insertLayoutInto(viewGroup)

                    // We need to mark the ListView and its empty view as pullable
                    // This is because they are not direct children of the ViewGroup
            .theseChildrenArePullable(getListView(), getListView().getEmptyView())
                    // Set the OnRefreshListener
            .listener(this).useViewDelegate(ImageView.class, new ViewDelegate() {
        @Override
        public boolean isReadyForPull(View view, float v, float v2) {
            return Boolean.TRUE;
        }
    }).options(optionsBuilder.build())
            // Finally commit the setup to our PullToRefreshLayout
            .setup(mPullToRefreshLayout);

    getListView().setChoiceMode(
            ListView.CHOICE_MODE_SINGLE);
}

@Override
public void onRefreshStarted(View view) {
    new AsyncTask<Void, Void, Void>() {
        /**
         * Override this method to perform a computation on a background thread. The
         * specified parameters are the parameters passed to {@link #execute}
         * by the caller of this task.
         * <p/>
         * This method can call {@link #publishProgress} to publish updates
         * on the UI thread.
         *
         * @param params The parameters of the task.
         * @return A result, defined by the subclass of this task.
         * @see #onPreExecute()
         * @see #onPostExecute
         * @see #publishProgress
         */
        @Override
        protected Void doInBackground(Void... params) {
            if (newsFeedProvider.requestFeedRefresh()) {
                listAdapter.updateShownNews();
            }
            return null;
        }

        /**
         * <p>Runs on the UI thread after {@link #doInBackground}. The
         * specified result is the value returned by {@link #doInBackground}.</p>
         * <p/>
         * <p>This method won't be invoked if the task was cancelled.</p>
         *
         * @param aVoid The result of the operation computed by {@link #doInBackground}.
         * @see #onPreExecute
         * @see #doInBackground
         * @see #onCancelled(Object)
         */
        @Override
        protected void onPostExecute(Void aVoid) {
            mPullToRefreshLayout.setRefreshComplete();
        }

        /**
         * <p>Applications should preferably override {@link #onCancelled(Object)}.
         * This method is invoked by the default implementation of
         * {@link #onCancelled(Object)}.</p>
         * <p/>
         * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
         * {@link #doInBackground(Object[])} has finished.</p>
         *
         * @see #onCancelled(Object)
         * @see #cancel(boolean)
         * @see #isCancelled()
         */
        @Override
        protected void onCancelled() {
            mPullToRefreshLayout.setRefreshComplete();
        }
    }.execute();
}


public interface NewsListFragmentListener {
    public void onNewsArticleSelected(int index);
}
}

NewsReaderActivity:

public class NewsReaderActivity extends FragmentActivity implements
    NewsListFragment.NewsListFragmentListener,
    NavigationDrawerFragment.NavigationDrawerCallbacks {
private Boolean isDualPane = Boolean.FALSE;
private NewsListFragment NEWS_FRAGMENT;
private WebViewerFragment WEB_FRAGMENT;
private int lastSelectedNavDrawerItem = 0;
private NavigationDrawerFragment mNavigationDrawerFragment;
private CharSequence mTitle;

private void restoreActionBar() {
    ActionBar actionBar = getActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setTitle(mTitle);
}

/**
 * Called when an item in the navigation drawer is selected.
 *
 * @param position
 */
@Override
public void onNavigationDrawerItemSelected(int position) {
    if (position == lastSelectedNavDrawerItem) {
        //We don't want to perform a useless fragment reload
        return;
    }
    else {
        lastSelectedNavDrawerItem = position;
    }
    //TODO The rest of the stuff
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    if (!mNavigationDrawerFragment.isDrawerOpen()) {
        getMenuInflater().inflate(R.menu.standard, menu);
        restoreActionBar();
        return true;
    }
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_settings:
            startActivity(new Intent(this, SettingsPreferenceActivity.class));
            break;
        default: //Up button
            return super.onOptionsItemSelected(item);
    }
    return true;
}

public void onSectionAttached(int number) {
    int shiftedPos = number + 1;
    mTitle = Utils.getString(this, "title_section" + shiftedPos, "");
    if (mTitle.toString().isEmpty()) {
        mTitle = getString(R.string.title_section1);
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_news);

    FragmentManager fragmentManager = getFragmentManager();

    mNavigationDrawerFragment = (NavigationDrawerFragment)
            fragmentManager.findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));

    NEWS_FRAGMENT =
            (NewsListFragment) getFragmentManager().findFragmentById(R.id.fragment_news);
    WEB_FRAGMENT =
            (WebViewerFragment) getFragmentManager().findFragmentById(R.id.fragment_web_viewer);

    View webView = findViewById(R.id.fragment_web_viewer);
    isDualPane = webView != null && webView.getVisibility() == View.VISIBLE;
    restoreState(savedInstanceState);
}

private void restoreState(Bundle savedInstanceState) {
    if (savedInstanceState != null) {
        int index = savedInstanceState.getInt("index", 0);
        NEWS_FRAGMENT.setSelection(index);
        onNewsArticleSelected(index);
    }
}


@Override
public void onNewsArticleSelected(int index) {
    showUrlInWebViewerFragment(index);
}

private void showUrlInWebViewerFragment(int index) {
    if (isDualPane) {
        WEB_FRAGMENT.loadUrl(SQLiteBridge.getSingleton().getNews().get(index).getLink());
    }
    else {
        Intent singleViewIntent = new Intent(this, WebViewerActivity.class);
        singleViewIntent.putExtra("index", index);
        startActivity(singleViewIntent);
    }
}
}

values-land/layouts.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="activity_news" type="layout">@layout/news_double_pane</item>
<bool name="has_two_panes">true</bool>
</resources>

values/layouts.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="activity_news" type="layout">@layout/news_single_pane</item>
<bool name="has_two_panes">true</bool>
</resources>

news_double_pane.xml:

<?xml version="1.0" encoding="utf-8"?>

<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
tools:context="org.jorge.lolin1.activities.MainActivity">
<fragment
    android:id="@+id/fragment_news"
    android:name="org.jorge.lolin1.frags.NewsListFragment"
    android:layout_width="@dimen/feed_item_length_percentage"
    android:layout_height="match_parent"/>
<fragment
    android:id="@+id/fragment_web_viewer"
    android:name="org.jorge.lolin1.frags.WebViewerFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/nothing_to_do_here"/>
<fragment
    android:id="@+id/navigation_drawer"
    android:name="org.jorge.lolin1.frags.NavigationDrawerFragment"
    android:layout_width="@dimen/navigation_drawer_width"
    android:layout_height="match_parent"
    android:layout_gravity="left"/>
</android.support.v4.widget.DrawerLayout>

news_single_pane.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.jorge.lolin1.activities.MainActivity">

<fragment android:id="@+id/fragment_news"
          android:name="org.jorge.lolin1.frags.NewsListFragment"
          android:layout_width="match_parent"
          android:layout_height="match_parent"/>
<fragment
    android:id="@+id/navigation_drawer"
    android:name="org.jorge.lolin1.frags.NavigationDrawerFragment"
    android:layout_width="@dimen/navigation_drawer_width"
    android:layout_height="match_parent"
    android:layout_gravity="left"/>
</android.support.v4.widget.DrawerLayout>

1 Answers1

0

Managed to solve it. It turned out to be quite a simple problem, one of those that show that you've coded enough for today :P

In the code given in the question android.support.v4.widget.DrawerLayout is the parent of all of the fragments (the navigation drawer, the list and the content stand) but, because of its behaviour, it allows the content stand to go over the list, completely covering it. So, the solution is as easy as moving the list and the content stand to an inner LinearLayout (for example).

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- BEGIN_INCLUDE(all) -->
<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="org.jorge.lolin1.activities.MainActivity">
    <fragment
        android:id="@+id/navigation_drawer"
        android:name="org.jorge.lolin1.frags.NavigationDrawerFragment"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        tools:layout="@layout/fragment_navigation_drawer"/>
    <LinearLayout android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:layout_marginBottom="@dimen/activity_vertical_margin"
                  android:layout_marginLeft="@dimen/activity_horizontal_margin"
                  android:layout_marginRight="@dimen/activity_horizontal_margin"
                  android:layout_marginTop="@dimen/activity_vertical_margin">
        <fragment
            android:id="@+id/fragment_news"
            android:name="org.jorge.lolin1.frags.NewsListFragment"
            android:layout_width="@dimen/feed_item_width"
            android:layout_height="match_parent"
            tools:layout="@layout/fragment_news_feed"/>
        <fragment
            android:id="@+id/fragment_web_viewer"
            android:name="org.jorge.lolin1.frags.WebViewerFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/nothing_to_do_here"
            tools:layout="@layout/fragment_web_viewer"/>
    </LinearLayout>
</android.support.v4.widget.DrawerLayout>
    <!-- END_INCLUDE(all) -->