1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package com.example.android.supportv4.widget; 19 20 import android.app.ActionBar; 21 import android.app.Activity; 22 import android.os.Build; 23 import android.os.Bundle; 24 import android.support.v4.widget.SlidingPaneLayout; 25 import android.view.MenuItem; 26 import android.view.View; 27 import android.view.ViewTreeObserver; 28 import android.widget.AdapterView; 29 import android.widget.ArrayAdapter; 30 import android.widget.ListView; 31 import android.widget.TextView; 32 import com.example.android.supportv4.Shakespeare; 33 import com.example.android.supportv4.R; 34 35 /** 36 * This example illustrates a common usage of SlidingPaneLayout in the Android support library. 37 * 38 * <p>A SlidingPaneLayout should be positioned at the top of your view hierarchy, placing it 39 * below the action bar but above your content views. It is ideal as a two-pane layout 40 * for larger screens, used in place of a horizontal LinearLayout.</p> 41 * 42 * <p>What separates SlidingPaneLayout from LinearLayout in this usage is that SlidingPaneLayout 43 * allows these wide, two-pane layouts to overlap when horizontal space is at a premium. The user 44 * can then access both panes by physically sliding the content pane into view or out of the way 45 * or implicitly by moving focus between the two panes. This can greatly simplify development 46 * of Android apps that support multiple form factors and screen sizes.</p> 47 * 48 * <p>When it comes to your navigation hierarchy, the left pane of a SlidingPaneLayout is always 49 * considered to be one level up from the right content pane. As such, your Action Bar's 50 * Up navigation should be enabled if the right pane is obscuring the left pane, and invoking it 51 * should open the panes, revealing the left pane for normal interaction. From this open state 52 * where the left pane is in primary focus, the Action Bar's Up affordance should act as if 53 * both panes were fully visible in the activity window and navigate to the activity one level up 54 * in the app's logical hierarchy. If the activity is the root of the application's task, the up 55 * affordance should be disabled when the sliding pane is open and showing the left pane. 56 * This code example illustrates this root activity case.</p> 57 * 58 * <p>Note that SlidingPaneLayout differs in usage from DrawerLayout. While DrawerLayout offers 59 * sliding utility drawers for extended navigation options and actions, the panes of a 60 * SlidingPaneLayout are firmly part of the content itself. If it would not make sense for 61 * both panes to be visible all the time on a sufficiently wide screen, DrawerLayout and its 62 * associated patterns are likely to be a better choice for your usage.</p> 63 */ 64 public class SlidingPaneLayoutActivity extends Activity { 65 private SlidingPaneLayout mSlidingLayout; 66 private ListView mList; 67 private TextView mContent; 68 69 private ActionBarHelper mActionBar; 70 71 @Override 72 protected void onCreate(Bundle savedInstanceState) { 73 super.onCreate(savedInstanceState); 74 75 setContentView(R.layout.sliding_pane_layout); 76 77 mSlidingLayout = (SlidingPaneLayout) findViewById(R.id.sliding_pane_layout); 78 mList = (ListView) findViewById(R.id.left_pane); 79 mContent = (TextView) findViewById(R.id.content_text); 80 81 mSlidingLayout.setPanelSlideListener(new SliderListener()); 82 mSlidingLayout.openPane(); 83 84 mList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, 85 Shakespeare.TITLES)); 86 mList.setOnItemClickListener(new ListItemClickListener()); 87 88 mActionBar = createActionBarHelper(); 89 mActionBar.init(); 90 91 mSlidingLayout.getViewTreeObserver().addOnGlobalLayoutListener(new FirstLayoutListener()); 92 } 93 94 @Override 95 public boolean onOptionsItemSelected(MenuItem item) { 96 /* 97 * The action bar up action should open the slider if it is currently closed, 98 * as the left pane contains content one level up in the navigation hierarchy. 99 */ 100 if (item.getItemId() == android.R.id.home && !mSlidingLayout.isOpen()) { 101 mSlidingLayout.smoothSlideOpen(); 102 return true; 103 } 104 return super.onOptionsItemSelected(item); 105 } 106 107 /** 108 * This list item click listener implements very simple view switching by changing 109 * the primary content text. The slider is closed when a selection is made to fully 110 * reveal the content. 111 */ 112 private class ListItemClickListener implements ListView.OnItemClickListener { 113 @Override 114 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 115 mContent.setText(Shakespeare.DIALOGUE[position]); 116 mActionBar.setTitle(Shakespeare.TITLES[position]); 117 mSlidingLayout.smoothSlideClosed(); 118 } 119 } 120 121 /** 122 * This panel slide listener updates the action bar accordingly for each panel state. 123 */ 124 private class SliderListener extends SlidingPaneLayout.SimplePanelSlideListener { 125 @Override 126 public void onPanelOpened(View panel) { 127 mActionBar.onPanelOpened(); 128 } 129 130 @Override 131 public void onPanelClosed(View panel) { 132 mActionBar.onPanelClosed(); 133 } 134 } 135 136 /** 137 * This global layout listener is used to fire an event after first layout occurs 138 * and then it is removed. This gives us a chance to configure parts of the UI 139 * that adapt based on available space after they have had the opportunity to measure 140 * and layout. 141 */ 142 private class FirstLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { 143 @Override 144 public void onGlobalLayout() { 145 mActionBar.onFirstLayout(); 146 mSlidingLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 147 } 148 } 149 150 /** 151 * Create a compatible helper that will manipulate the action bar if available. 152 */ 153 private ActionBarHelper createActionBarHelper() { 154 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 155 return new ActionBarHelperICS(); 156 } else { 157 return new ActionBarHelper(); 158 } 159 } 160 161 /** 162 * Stub action bar helper; this does nothing. 163 */ 164 private class ActionBarHelper { 165 public void init() {} 166 public void onPanelClosed() {} 167 public void onPanelOpened() {} 168 public void onFirstLayout() {} 169 public void setTitle(CharSequence title) {} 170 } 171 172 /** 173 * Action bar helper for use on ICS and newer devices. 174 */ 175 private class ActionBarHelperICS extends ActionBarHelper { 176 private final ActionBar mActionBar; 177 private CharSequence mDrawerTitle; 178 private CharSequence mTitle; 179 180 ActionBarHelperICS() { 181 mActionBar = getActionBar(); 182 } 183 184 @Override 185 public void init() { 186 mActionBar.setDisplayHomeAsUpEnabled(true); 187 mActionBar.setHomeButtonEnabled(true); 188 mTitle = mDrawerTitle = getTitle(); 189 } 190 191 @Override 192 public void onPanelClosed() { 193 super.onPanelClosed(); 194 mActionBar.setDisplayHomeAsUpEnabled(true); 195 mActionBar.setHomeButtonEnabled(true); 196 mActionBar.setTitle(mTitle); 197 } 198 199 @Override 200 public void onPanelOpened() { 201 super.onPanelOpened(); 202 mActionBar.setHomeButtonEnabled(false); 203 mActionBar.setDisplayHomeAsUpEnabled(false); 204 mActionBar.setTitle(mDrawerTitle); 205 } 206 207 @Override 208 public void onFirstLayout() { 209 if (mSlidingLayout.canSlide() && !mSlidingLayout.isOpen()) { 210 onPanelClosed(); 211 } else { 212 onPanelOpened(); 213 } 214 } 215 216 @Override 217 public void setTitle(CharSequence title) { 218 mTitle = title; 219 } 220 } 221 222 } 223