Search code examples
androidandroid-layoutandroid-fragmentsandroid-listfragment

Custom positioning of ListFragment


I have an Activity that loads a FrameLayoutcontaining a SearchView and Button when created. The button's onClick method loads a custom ListFragment on top of the main FrameLayout.

I override the onCreate method of the ListFragment to load my custom ArrayAdapterand populate the list with values from a string array that I manually create for now. All of this works properly but I would like to load the ListFragment at the bottom of the screen.

I have tried changing the gravity of the main FrameLayout to bottom, since it is the parent of the ListFragment but this makes the SearchView and Button drop to the bottom of the screen along with the ListFragment.

In this example, I am loading three rows in the list. How can I move the ListFragment down so that only the first row is visible at the bottom of the screen with the other two rows below it (off the screen)?

My MapActivity is the main Activity

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MapActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_map);

    }

    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            return inflater.inflate(R.layout.fragment_map, container, false);
        }
    }

    // Define the onShowTimesButtonClick listener
    public void onShowTimesButtonClick(View view){

        // Instantiate timeListFragment
        TimeListFragment timeListFragment = new TimeListFragment();

        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.add(R.id.container, timeListFragment, "timeList");
        transaction.commit();
    }
}

The layout of the MapActivity

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapActivity"
    tools:ignore="MergeRootFrame"
    android:clickable="true"
    android:focusable="false"
    android:focusableInTouchMode="false">

    <SearchView
        android:layout_width="300dp"
        android:layout_height="50dp"
        android:id="@+id/searchBar"
        android:layout_gravity="start|top"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginStart="20dp"
        android:background="#656565"
        android:clickable="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:inputType="text" />

    <Button
        android:id="@+id/timesButton"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:layout_gravity="top|center"
        android:layout_marginTop="90dp"
        android:text="@string/times_button"
        android:onClick="onShowTimesButtonClick"/>

</FrameLayout>

TimeListFragment is my custom ListFragment.

import android.app.ListFragment;
import android.os.Bundle;
import android.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout.LayoutParams;

/**
 * A simple {@link Fragment} subclass.
 */
public class TimeListFragment extends ListFragment {

    public TimeListFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Temporary time data
        String[] times = new String[]{"1:00", "0:30", "0:45"};

        // Load the time data
        setListAdapter(new TimesListArrayAdapter(getActivity(), R.layout.layout_times_list_row, R.id.listText, times));
    }

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

        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        layoutParams.gravity = Gravity.BOTTOM;

        container.setLayoutParams(layoutParams);

        return view;
    }
}

The layout for TimeListFragment

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="8dp"
    android:paddingRight="8dp"
    android:gravity="bottom">

    <ListView android:id= "@id/android:list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:drawSelectorOnTop="false"/>

    <TextView android:id="@id/android:empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="No data"/>
</LinearLayout>

Solution

  • Here is what I have so far. I can move the ListFragment to the bottom of the screen by setting the gravity to bottom. In the onCreateView method of the TimeListFragment, I was applying the layoutParams to the container; according to the Android documentation, this container is the parent view that the fragment's UI is attached to. In order to apply the layoutParams to the fragment itself, I had to find the fragment view first by calling the findViewById on the inflated view.

    The correct code for the onCreateView is shown below

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.layout_times_list, container, false);
    
            View fragmentView = view.findViewById(R.id.timesList);
    
            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            layoutParams.gravity = Gravity.BOTTOM;
    
            fragmentView.setLayoutParams(layoutParams);
    
            return view;
        }