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