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