In this tutorial you will learn how to make make a two pane layout in Android and thus making your application responsive in design. Be it on phone or tablet, your application should look flawless, one of the commonly used design pattern when on tablet is two pane also known master-detail pattern.

In this tutorial you will code an application that looks a certain way on phone and a different way on tablet. The complete code is available on this GitHub Repo.

You will be developing a mock settings application that has 3 options, “Network”, “Storage” and “Display”. On a normal phone you will show list of these options which when clicked will open the details for that option. On a tablet you will be showing the two pane layout in which when an option is clicked in the left pane will update the content in right pane.

First you will be developing the layout for a mobile device and then you will tweak it to adapt on tablets.

Setup

There is no special dependencies required for making a two pane layout so the setup is very simple.

Create a new Android Studio Project. Now you have a MainActivity. Done!

The main_Activity.xml layout file contains the following code.

activity_main.xml <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> </FrameLayout> 1 2 3 4 5 6 7 8 9 10 <? xml version = "1.0" encoding = "utf-8" ?> < FrameLayout xmlns : android = "http://schemas.android.com/apk/res/android" xmlns : app = "http://schemas.android.com/apk/res-auto" xmlns : tools = "http://schemas.android.com/tools" android : id = "@+id/container" android : layout_width = "match_parent" android : layout_height = "match_parent" tools : context = ".MainActivity" > < / FrameLayout >

Creating the Options Layout

Create a new file named fragment_settings_options_view.xml. This will be our layout file for the 3 setting options that we have.

fragment_settings_options_view.xml <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:id="@+id/displayOption" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?selectableItemBackground" android:clickable="true" android:focusable="true" android:gravity="center_vertical" android:orientation="horizontal" android:padding="16dp"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:src="@mipmap/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:text="@string/display" android:textSize="20sp" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="0.5dp" android:background="@android:color/darker_gray" /> <LinearLayout android:id="@+id/storageOption" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?selectableItemBackground" android:clickable="true" android:focusable="true" android:gravity="center_vertical" android:orientation="horizontal" android:padding="16dp"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:src="@mipmap/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:text="@string/storage" android:textSize="20sp" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="0.5dp" android:background="@android:color/darker_gray" /> <LinearLayout android:id="@+id/networkOption" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?selectableItemBackground" android:clickable="true" android:focusable="true" android:gravity="center_vertical" android:orientation="horizontal" android:padding="16dp"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:src="@mipmap/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:text="@string/network" android:textSize="20sp" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="0.5dp" android:background="@android:color/darker_gray" /> </LinearLayout> </ScrollView> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 <? xml version = "1.0" encoding = "utf-8" ?> < ScrollView xmlns : android = "http://schemas.android.com/apk/res/android" android : layout_width = "match_parent" android : layout_height = "match_parent" android : orientation = "vertical" > < LinearLayout android : layout_width = "match_parent" android : layout_height = "wrap_content" android : orientation = "vertical" > < LinearLayout android : id = "@+id/displayOption" android : layout_width = "match_parent" android : layout_height = "wrap_content" android : background = "?selectableItemBackground" android : clickable = "true" android : focusable = "true" android : gravity = "center_vertical" android : orientation = "horizontal" android : padding = "16dp" > < ImageView android : layout_width = "40dp" android : layout_height = "40dp" android : src = "@mipmap/ic_launcher" / > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : layout_marginLeft = "16dp" android : layout_marginStart = "16dp" android : text = "@string/display" android : textSize = "20sp" / > < / LinearLayout > < View android : layout_width = "match_parent" android : layout_height = "0.5dp" android : background = "@android:color/darker_gray" / > < LinearLayout android : id = "@+id/storageOption" android : layout_width = "match_parent" android : layout_height = "wrap_content" android : background = "?selectableItemBackground" android : clickable = "true" android : focusable = "true" android : gravity = "center_vertical" android : orientation = "horizontal" android : padding = "16dp" > < ImageView android : layout_width = "40dp" android : layout_height = "40dp" android : src = "@mipmap/ic_launcher" / > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : layout_marginLeft = "16dp" android : layout_marginStart = "16dp" android : text = "@string/storage" android : textSize = "20sp" / > < / LinearLayout > < View android : layout_width = "match_parent" android : layout_height = "0.5dp" android : background = "@android:color/darker_gray" / > < LinearLayout android : id = "@+id/networkOption" android : layout_width = "match_parent" android : layout_height = "wrap_content" android : background = "?selectableItemBackground" android : clickable = "true" android : focusable = "true" android : gravity = "center_vertical" android : orientation = "horizontal" android : padding = "16dp" > < ImageView android : layout_width = "40dp" android : layout_height = "40dp" android : src = "@mipmap/ic_launcher" / > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : layout_marginLeft = "16dp" android : layout_marginStart = "16dp" android : text = "@string/network" android : textSize = "20sp" / > < / LinearLayout > < View android : layout_width = "match_parent" android : layout_height = "0.5dp" android : background = "@android:color/darker_gray" / > < / LinearLayout > < / ScrollView >

Now create a Fragment class for the same called SettingOptionsFragment.

SettingOptionsFragment public class SettingOptionsFragment extends Fragment { @Override public void onAttach(Context context) { super.onAttach(context); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_settings_options_view, container, false); return rootView; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class SettingOptionsFragment extends Fragment { @ Override public void onAttach ( Context context ) { super . onAttach ( context ) ; } @ Nullable @ Override public View onCreateView ( @ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) { View rootView = inflater . inflate ( R . layout . fragment_settings_options_view , container , false ) ; return rootView ; } }

Load this fragment!

public class MainActivity extends AppCompatActivity { private FragmentManager fragmentManager; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragmentManager = getSupportFragmentManager(); if (savedInstanceState == null) { fragmentManager.beginTransaction() .add(R.id.container, new SettingOptionsFragment()) .commit(); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class MainActivity extends AppCompatActivity { private FragmentManager fragmentManager ; protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_main ) ; fragmentManager = getSupportFragmentManager ( ) ; if ( savedInstanceState == null ) { fragmentManager . beginTransaction ( ) . add ( R . id . container , new SettingOptionsFragment ( ) ) . commit ( ) ; } } }

Now if you run the application it will look like this.

Lets show a new activity when any of the option is clicked.

Creating Detail Layout

Create a new Activity named SettingsDetailActivity. Below is the layout file of this activity.

activity_setting_details <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/settingsContainer" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".SettingDetailsActivity"> </FrameLayout> 1 2 3 4 5 6 7 8 9 10 <? xml version = "1.0" encoding = "utf-8" ?> < FrameLayout xmlns : android = "http://schemas.android.com/apk/res/android" xmlns : app = "http://schemas.android.com/apk/res-auto" xmlns : tools = "http://schemas.android.com/tools" android : id = "@+id/settingsContainer" android : layout_width = "match_parent" android : layout_height = "match_parent" tools : context = ".SettingDetailsActivity" > < / FrameLayout >

Now create three fragment files for each option, “network”, “display” and “storage”.

Network Settings

fragment_network_settings.xml

fragment_network_settings.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/network" android:textSize="40sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/network_description"/> </LinearLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns : android = "http://schemas.android.com/apk/res/android" android : layout_width = "match_parent" android : layout_height = "match_parent" android : orientation = "vertical" android : padding = "16dp" > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "@string/network" android : textSize = "40sp" / > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "@string/network_description" / > < / LinearLayout >

NetworkSettingsFragment

NetworkSettingsFragment public class NetworkSettingsFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_network_settings, container, false); return rootView; } } 1 2 3 4 5 6 7 8 9 10 public class NetworkSettingsFragment extends Fragment { @ Nullable @ Override public View onCreateView ( @ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) { View rootView = inflater . inflate ( R . layout . fragment_network_settings , container , false ) ; return rootView ; } }

Display Settings

fragment_display_settings.xml

fragment_display_settings.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/display" android:textSize="40sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/display_description"/> </LinearLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns : android = "http://schemas.android.com/apk/res/android" android : layout_width = "match_parent" android : layout_height = "match_parent" android : orientation = "vertical" android : padding = "16dp" > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "@string/display" android : textSize = "40sp" / > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "@string/display_description" / > < / LinearLayout >

DisplaySettingsFragment

DisplaySettingsFragment public class DisplaySettingsFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_display_settings, container, false); return rootView; } } 1 2 3 4 5 6 7 8 9 10 public class DisplaySettingsFragment extends Fragment { @ Nullable @ Override public View onCreateView ( @ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) { View rootView = inflater . inflate ( R . layout . fragment_display_settings , container , false ) ; return rootView ; } }

Storage Settings

fragment_storage_settings.xml

fragment_storage_settings.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/storage" android:textSize="40sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/storage_description"/> </LinearLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns : android = "http://schemas.android.com/apk/res/android" android : layout_width = "match_parent" android : layout_height = "match_parent" android : orientation = "vertical" android : padding = "16dp" > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "@string/storage" android : textSize = "40sp" / > < TextView android : layout_width = "wrap_content" android : layout_height = "wrap_content" android : text = "@string/storage_description" / > < / LinearLayout >

StorageSettingsFragment

StorageSettingsFragment public class StorageSettingsFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_storage_settings, container, false); return rootView; } } 1 2 3 4 5 6 7 8 9 10 public class StorageSettingsFragment extends Fragment { @ Nullable @ Override public View onCreateView ( @ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) { View rootView = inflater . inflate ( R . layout . fragment_storage_settings , container , false ) ; return rootView ; } }

Before loading this fragment in SettingDetailsActivity, we first have to determine which option the user selected in the MainActivity.

Fragment-Activity Communication

Lets go back to the MainActivity and SettingOptionsFragment. In SettingOptionsFragment you have to determine which option did the user clicked on and notify it to MainActivity. You will do this by using callbacks.

Update your SettingOptionsFragment by adding an interface OnOptionClickListener that contains one method onOptionSelected(String).

SettingOptionsFragment public class SettingOptionsFragment extends Fragment { interface OnOptionClickListener { void onOptionSelected(String option); } private OnOptionClickListener mCallback; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_settings_options_view, container, false); return rootView; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class SettingOptionsFragment extends Fragment { interface OnOptionClickListener { void onOptionSelected ( String option ) ; } private OnOptionClickListener mCallback ; @ Nullable @ Override public View onCreateView ( @ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) { View rootView = inflater . inflate ( R . layout . fragment_settings_options_view , container , false ) ; return rootView ; } }

MainActivity will implement this interface.

MainActivity public class MainActivity extends AppCompatActivity implements SettingOptionsFragment.OnOptionClickListener { private FragmentManager fragmentManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragmentManager = getSupportFragmentManager(); if (savedInstanceState == null) { fragmentManager.beginTransaction() .add(R.id.container, new SettingOptionsFragment()) .commit(); } } @Override public void onOptionSelected(String option) { } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class MainActivity extends AppCompatActivity implements SettingOptionsFragment . OnOptionClickListener { private FragmentManager fragmentManager ; @ Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_main ) ; fragmentManager = getSupportFragmentManager ( ) ; if ( savedInstanceState == null ) { fragmentManager . beginTransaction ( ) . add ( R . id . container , new SettingOptionsFragment ( ) ) . commit ( ) ; } } @ Override public void onOptionSelected ( String option ) { } }

Now the SettingOptionsFragment needs to get an instance to the MainActivity that implements OnOptionClickListener. You can grab the Activity in the onAttach method of a fragment.

SettingOptionsFragment public class SettingOptionsFragment extends Fragment { interface OnOptionClickListener { void onOptionSelected(String option); } private OnOptionClickListener mCallback; @Override public void onAttach(Context context) { super.onAttach(context); try { mCallback = (OnOptionClickListener) context; } catch (Exception e) { throw new ClassCastException(context.toString() + " must implement SettingOptionsFragment.OnOptionClickListener"); } } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_settings_options_view, container, false); return rootView; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class SettingOptionsFragment extends Fragment { interface OnOptionClickListener { void onOptionSelected ( String option ) ; } private OnOptionClickListener mCallback ; @ Override public void onAttach ( Context context ) { super . onAttach ( context ) ; try { mCallback = ( OnOptionClickListener ) context ; } catch ( Exception e ) { throw new ClassCastException ( context . toString ( ) + " must implement SettingOptionsFragment.OnOptionClickListener" ) ; } } @ Nullable @ Override public View onCreateView ( @ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) { View rootView = inflater . inflate ( R . layout . fragment_settings_options_view , container , false ) ; return rootView ; } }

Lets add click listener on the options and notify Activity about the click.

SettingOptionsFragment public class SettingOptionsFragment extends Fragment { interface OnOptionClickListener { void onOptionSelected(String option); } private OnOptionClickListener mCallback; @Override public void onAttach(Context context) { super.onAttach(context); try { mCallback = (OnOptionClickListener) context; } catch (Exception e) { throw new ClassCastException(context.toString() + " must implement SettingOptionsFragment.OnOptionClickListener"); } } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_settings_options_view, container, false); LinearLayout mNetworkOption = rootView.findViewById(R.id.networkOption); LinearLayout mStorageOption = rootView.findViewById(R.id.storageOption); LinearLayout mDisplayOption = rootView.findViewById(R.id.displayOption); mNetworkOption.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCallback.onOptionSelected("network"); } }); mStorageOption.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCallback.onOptionSelected("storage"); } }); mDisplayOption.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCallback.onOptionSelected("display"); } }); return rootView; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public class SettingOptionsFragment extends Fragment { interface OnOptionClickListener { void onOptionSelected ( String option ) ; } private OnOptionClickListener mCallback ; @ Override public void onAttach ( Context context ) { super . onAttach ( context ) ; try { mCallback = ( OnOptionClickListener ) context ; } catch ( Exception e ) { throw new ClassCastException ( context . toString ( ) + " must implement SettingOptionsFragment.OnOptionClickListener" ) ; } } @ Nullable @ Override public View onCreateView ( @ NonNull LayoutInflater inflater , @ Nullable ViewGroup container , @ Nullable Bundle savedInstanceState ) { View rootView = inflater . inflate ( R . layout . fragment_settings_options_view , container , false ) ; LinearLayout mNetworkOption = rootView . findViewById ( R . id . networkOption ) ; LinearLayout mStorageOption = rootView . findViewById ( R . id . storageOption ) ; LinearLayout mDisplayOption = rootView . findViewById ( R . id . displayOption ) ; mNetworkOption . setOnClickListener ( new View . OnClickListener ( ) { @ Override public void onClick ( View v ) { mCallback . onOptionSelected ( "network" ) ; } } ) ; mStorageOption . setOnClickListener ( new View . OnClickListener ( ) { @ Override public void onClick ( View v ) { mCallback . onOptionSelected ( "storage" ) ; } } ) ; mDisplayOption . setOnClickListener ( new View . OnClickListener ( ) { @ Override public void onClick ( View v ) { mCallback . onOptionSelected ( "display" ) ; } } ) ; return rootView ; } }

In the MainActivity launch an Intent to start SettingDetailsActivity.

MainActivity public class MainActivity extends AppCompatActivity implements SettingOptionsFragment.OnOptionClickListener { private FragmentManager fragmentManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragmentManager = getSupportFragmentManager(); if (savedInstanceState == null) { fragmentManager.beginTransaction() .add(R.id.container, new SettingOptionsFragment()) .commit(); } } @Override public void onOptionSelected(String option) { Intent intent = new Intent(this, SettingDetailsActivity.class); intent.putExtra(SettingDetailsActivity.EXTRA_SETTING_OPTION, option); startActivity(intent); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class MainActivity extends AppCompatActivity implements SettingOptionsFragment . OnOptionClickListener { private FragmentManager fragmentManager ; @ Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_main ) ; fragmentManager = getSupportFragmentManager ( ) ; if ( savedInstanceState == null ) { fragmentManager . beginTransaction ( ) . add ( R . id . container , new SettingOptionsFragment ( ) ) . commit ( ) ; } } @ Override public void onOptionSelected ( String option ) { Intent intent = new Intent ( this , SettingDetailsActivity . class ) ; intent . putExtra ( SettingDetailsActivity . EXTRA_SETTING_OPTION , option ) ; startActivity ( intent ) ; } }

Update the SettingDetailsActivity to load the required fragment.

SettingDetailsActivity public class SettingDetailsActivity extends AppCompatActivity { public static final String EXTRA_SETTING_OPTION = "option"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_setting_details); String option = getIntent().getStringExtra(EXTRA_SETTING_OPTION); FragmentManager fragmentManager = getSupportFragmentManager(); if (option == null) { finish(); return; } switch (option) { case "network": { fragmentManager.beginTransaction() .add(R.id.settingsContainer, new NetworkSettingsFragment()) .commit(); break; } case "display": { fragmentManager.beginTransaction() .add(R.id.settingsContainer, new DisplaySettingsFragment()) .commit(); break; } case "storage": { fragmentManager.beginTransaction() .add(R.id.settingsContainer, new StorageSettingsFragment()) .commit(); break; } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class SettingDetailsActivity extends AppCompatActivity { public static final String EXTRA_SETTING_OPTION = "option" ; @ Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_setting_details ) ; String option = getIntent ( ) . getStringExtra ( EXTRA_SETTING_OPTION ) ; FragmentManager fragmentManager = getSupportFragmentManager ( ) ; if ( option == null ) { finish ( ) ; return ; } switch ( option ) { case "network" : { fragmentManager . beginTransaction ( ) . add ( R . id . settingsContainer , new NetworkSettingsFragment ( ) ) . commit ( ) ; break ; } case "display" : { fragmentManager . beginTransaction ( ) . add ( R . id . settingsContainer , new DisplaySettingsFragment ( ) ) . commit ( ) ; break ; } case "storage" : { fragmentManager . beginTransaction ( ) . add ( R . id . settingsContainer , new StorageSettingsFragment ( ) ) . commit ( ) ; break ; } } } }

Now launch the app and select an option to open the detail activity.

Two Pane Layout

Let’s do the main thing that you are here for, adding two pane functionality when in tablet mode.

First you will have to create a layout folder for devices with size minimum of width 600dp. So whenever a devices is greater than 600dp in width, the layout files in this folder will be used over the general layout files. Let’s first create this folder.

Right click on res -> New -> Android Resource Directory. A dialog will open. Select the Resource Type to be ‘layout’. Select the ‘Smallest Screen Width’ and set the value to 600. Now a new folder named layout-sw600dp will be created.

In the created folder create a new layout file named activity_main.xml. When on a device greater than width 600 this layout file will be used by the MainActivity.

The layout in this file will be different from the original activity_main.xml.

activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" tools:context=".MainActivity"> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" tools:context=".MainActivity"> </FrameLayout> <View android:layout_width="1dp" android:layout_height="wrap_content" android:background="@android:color/darker_gray"/> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/detailContainer" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="7" tools:context=".MainActivity"> </FrameLayout> </LinearLayout> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout xmlns : android = "http://schemas.android.com/apk/res/android" xmlns : app = "http://schemas.android.com/apk/res-auto" xmlns : tools = "http://schemas.android.com/tools" android : layout_width = "match_parent" android : layout_height = "match_parent" android : orientation = "horizontal" tools : context = ".MainActivity" > < FrameLayout xmlns : android = "http://schemas.android.com/apk/res/android" xmlns : tools = "http://schemas.android.com/tools" android : id = "@+id/container" android : layout_width = "0dp" android : layout_height = "match_parent" android : layout_weight = "3" tools : context = ".MainActivity" > < / FrameLayout > < View android : layout_width = "1dp" android : layout_height = "wrap_content" android : background = "@android:color/darker_gray" / > < FrameLayout xmlns : android = "http://schemas.android.com/apk/res/android" xmlns : tools = "http://schemas.android.com/tools" android : id = "@+id/detailContainer" android : layout_width = "0dp" android : layout_height = "match_parent" android : layout_weight = "7" tools : context = ".MainActivity" > < / FrameLayout > < / LinearLayout >

If you compare with the original file you will find that this layout has a new FrameLayout added with id detailContainer.

How to know when the app is on a tablet?

So you want to know when the application is loaded on tablet. As I told you when on a device with width greater than 600 the 2nd activity_main.xml file will be loaded. So you will check the presence of the new FrameLayout added only in the 2nd layout file, if it is present then the app in on a tablet if not then it is on a phone.

MainActivity.java public class MainActivity extends AppCompatActivity implements SettingOptionsFragment.OnOptionClickListener { private boolean isTwoPane; private FragmentManager fragmentManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragmentManager = getSupportFragmentManager(); if (findViewById(R.id.detailContainer) != null) { isTwoPane = true; } else { isTwoPane = false; } if (savedInstanceState == null) { fragmentManager.beginTransaction() .add(R.id.container, new SettingOptionsFragment()) .commit(); } } @Override public void onOptionSelected(String option) { Intent intent = new Intent(this, SettingDetailsActivity.class); intent.putExtra(SettingDetailsActivity.EXTRA_SETTING_OPTION, option); startActivity(intent); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class MainActivity extends AppCompatActivity implements SettingOptionsFragment . OnOptionClickListener { private boolean isTwoPane ; private FragmentManager fragmentManager ; @ Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_main ) ; fragmentManager = getSupportFragmentManager ( ) ; if ( findViewById ( R . id . detailContainer ) != null ) { isTwoPane = true ; } else { isTwoPane = false ; } if ( savedInstanceState == null ) { fragmentManager . beginTransaction ( ) . add ( R . id . container , new SettingOptionsFragment ( ) ) . commit ( ) ; } } @ Override public void onOptionSelected ( String option ) { Intent intent = new Intent ( this , SettingDetailsActivity . class ) ; intent . putExtra ( SettingDetailsActivity . EXTRA_SETTING_OPTION , option ) ; startActivity ( intent ) ; } }

All that is remaining is to behave differently when you know you are dealing with a tablet i.e. rather than starting an Intent when an option is selected, change the fragment in the right hand side.

This is the final code for MainActivity.

MainActivity.java public class MainActivity extends AppCompatActivity implements SettingOptionsFragment.OnOptionClickListener { private boolean isTwoPane; private FragmentManager fragmentManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragmentManager = getSupportFragmentManager(); if (findViewById(R.id.detailContainer) != null) { isTwoPane = true; } else { isTwoPane = false; } if (savedInstanceState == null) { fragmentManager.beginTransaction() .add(R.id.container, new SettingOptionsFragment()) .commit(); } //Load Display Settings Fragment by default in the details pane if (isTwoPane) { fragmentManager.beginTransaction() .replace(R.id.detailContainer, new DisplaySettingsFragment()) .commit(); } } @Override public void onOptionSelected(String option) { if (isTwoPane) { switch (option) { case "network": { fragmentManager.beginTransaction() .replace(R.id.detailContainer, new NetworkSettingsFragment()) .commit(); break; } case "display": { fragmentManager.beginTransaction() .replace(R.id.detailContainer, new DisplaySettingsFragment()) .commit(); break; } case "storage": { fragmentManager.beginTransaction() .replace(R.id.detailContainer, new StorageSettingsFragment()) .commit(); break; } } } else { Intent intent = new Intent(this, SettingDetailsActivity.class); intent.putExtra(SettingDetailsActivity.EXTRA_SETTING_OPTION, option); startActivity(intent); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public class MainActivity extends AppCompatActivity implements SettingOptionsFragment . OnOptionClickListener { private boolean isTwoPane ; private FragmentManager fragmentManager ; @ Override protected void onCreate ( Bundle savedInstanceState ) { super . onCreate ( savedInstanceState ) ; setContentView ( R . layout . activity_main ) ; fragmentManager = getSupportFragmentManager ( ) ; if ( findViewById ( R . id . detailContainer ) != null ) { isTwoPane = true ; } else { isTwoPane = false ; } if ( savedInstanceState == null ) { fragmentManager . beginTransaction ( ) . add ( R . id . container , new SettingOptionsFragment ( ) ) . commit ( ) ; } //Load Display Settings Fragment by default in the details pane if ( isTwoPane ) { fragmentManager . beginTransaction ( ) . replace ( R . id . detailContainer , new DisplaySettingsFragment ( ) ) . commit ( ) ; } } @ Override public void onOptionSelected ( String option ) { if ( isTwoPane ) { switch ( option ) { case "network" : { fragmentManager . beginTransaction ( ) . replace ( R . id . detailContainer , new NetworkSettingsFragment ( ) ) . commit ( ) ; break ; } case "display" : { fragmentManager . beginTransaction ( ) . replace ( R . id . detailContainer , new DisplaySettingsFragment ( ) ) . commit ( ) ; break ; } case "storage" : { fragmentManager . beginTransaction ( ) . replace ( R . id . detailContainer , new StorageSettingsFragment ( ) ) . commit ( ) ; break ; } } } else { Intent intent = new Intent ( this , SettingDetailsActivity . class ) ; intent . putExtra ( SettingDetailsActivity . EXTRA_SETTING_OPTION , option ) ; startActivity ( intent ) ; } } }

That is it for this tutorial. You can find the complete code on this GitHub repo.

Just enough Dart for Flutter.

Guide to Notifications in Android.

How to make Bottom Sheet in Android.

Guide to Integrating AdMob in your Android App.