Three pane layout
Implement basic behavior of the new layout. Supports collapsing/expanding message list on portrait. TODO Collapsing the middle pane should cancel the selection mode on message list TODO Implement animation TODO On STATE_PORTRAIT_MIDDLE_EXPANDED state, right pane should be pushed out, rather than squished. Change-Id: I0306516845de3a1f05a102864c3dc4aba809a49a
This commit is contained in:
parent
cd2e98d000
commit
8818a658a1
66
res/layout-port/three_pane.xml
Normal file
66
res/layout-port/three_pane.xml
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- ThreePaneLayout is based on LinearLayout with the orientation always horizontal -->
|
||||
|
||||
<!-- for portrait -->
|
||||
|
||||
<com.android.email.activity.ThreePaneLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:splitMotionEvents="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/left_pane"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/middle_pane"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="2"
|
||||
/>
|
||||
<!-- STOPSHIP Don't use hardcoded color -->
|
||||
<View
|
||||
android:id="@+id/collapser"
|
||||
android:layout_width="30dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0"
|
||||
android:background="#ff0"
|
||||
/>
|
||||
<FrameLayout
|
||||
android:id="@+id/right_pane_with_fog"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="2"
|
||||
>
|
||||
<FrameLayout
|
||||
android:id="@+id/right_pane"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
<View
|
||||
android:id="@+id/fogged_glass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#c0ffffff"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</com.android.email.activity.ThreePaneLayout>
|
@ -14,29 +14,13 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:splitMotionEvents="true"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/left_pane"
|
||||
android:layout_width="300dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
<include
|
||||
android:id="@+id/three_pane"
|
||||
layout="@layout/three_pane"
|
||||
/>
|
||||
<FrameLayout
|
||||
android:id="@+id/middle_pane"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<FrameLayout
|
||||
android:id="@+id/right_pane"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="2"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
45
res/layout/three_pane.xml
Normal file
45
res/layout/three_pane.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2010 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- ThreePaneLayout is based on LinearLayout with the orientation always horizontal -->
|
||||
|
||||
<!-- for landscape -->
|
||||
|
||||
<com.android.email.activity.ThreePaneLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:splitMotionEvents="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/left_pane"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<FrameLayout
|
||||
android:id="@+id/middle_pane"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="3"
|
||||
/>
|
||||
<FrameLayout
|
||||
android:id="@+id/right_pane"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="6"
|
||||
/>
|
||||
</com.android.email.activity.ThreePaneLayout>
|
@ -66,9 +66,7 @@ class MessageListXLFragmentManager {
|
||||
/** Current message id. (-1 = not selected) */
|
||||
private long mMessageId = -1;
|
||||
|
||||
private View mLeftPane;
|
||||
private View mMiddlePane;
|
||||
private View mRightPane;
|
||||
private ThreePaneLayout mThreePane;
|
||||
|
||||
private MailboxListFragment mMailboxListFragment;
|
||||
private MessageListFragment mMessageListFragment;
|
||||
@ -123,9 +121,7 @@ class MessageListXLFragmentManager {
|
||||
* the constructor.)
|
||||
*/
|
||||
public void onActivityViewReady() {
|
||||
mLeftPane = mTargetActivity.findViewById(R.id.left_pane);
|
||||
mMiddlePane = mTargetActivity.findViewById(R.id.middle_pane);
|
||||
mRightPane = mTargetActivity.findViewById(R.id.right_pane);
|
||||
mThreePane = (ThreePaneLayout) mTargetActivity.findViewById(R.id.three_pane);
|
||||
}
|
||||
|
||||
/** Set callback for fragment. */
|
||||
@ -312,7 +308,7 @@ class MessageListXLFragmentManager {
|
||||
// We can put it directly in the layout file, but then it'll have slightly different
|
||||
// lifecycle as the other fragments. Let's create it here this way for now.
|
||||
MailboxListFragment f = new MailboxListFragment();
|
||||
ft.replace(R.id.left_pane, f);
|
||||
ft.replace(mThreePane.getLeftPaneId(), f);
|
||||
}
|
||||
if (mMessageListFragment != null) {
|
||||
ft.remove(mMessageListFragment);
|
||||
@ -400,7 +396,7 @@ class MessageListXLFragmentManager {
|
||||
f.doAutoRefresh();
|
||||
}
|
||||
FragmentTransaction ft = mFragmentManager.openTransaction()
|
||||
.replace(R.id.middle_pane, f);
|
||||
.replace(mThreePane.getMiddlePaneId(), f);
|
||||
if (mMessageViewFragment != null) {
|
||||
// Message view will disappear.
|
||||
ft.remove(mMessageViewFragment);
|
||||
@ -467,7 +463,7 @@ class MessageListXLFragmentManager {
|
||||
|
||||
// We don't use the built-in back mechanism.
|
||||
// See MessageListXL.onBackPressed().
|
||||
mFragmentManager.openTransaction().replace(R.id.right_pane, f)
|
||||
mFragmentManager.openTransaction().replace(mThreePane.getRightPaneId(), f)
|
||||
// .addToBackStack(null)
|
||||
.commit();
|
||||
} else {
|
||||
@ -490,14 +486,12 @@ class MessageListXLFragmentManager {
|
||||
}
|
||||
|
||||
private void hideMessageBoxList() {
|
||||
mLeftPane.setVisibility(View.GONE);
|
||||
mRightPane.setVisibility(View.VISIBLE);
|
||||
mThreePane.showRightPane(true);
|
||||
}
|
||||
|
||||
private void hideMessageView() {
|
||||
mMessageId = -1;
|
||||
mRightPane.setVisibility(View.GONE);
|
||||
mLeftPane.setVisibility(View.VISIBLE);
|
||||
mThreePane.showRightPane(false);
|
||||
if (mMessageViewFragment != null) {
|
||||
mFragmentManager.openTransaction().remove(mMessageViewFragment).commit();
|
||||
mMessageViewFragment = null;
|
||||
|
265
src/com/android/email/activity/ThreePaneLayout.java
Normal file
265
src/com/android/email/activity/ThreePaneLayout.java
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
// TODO Collapsing the middle pane should cancel the selection mode on message list
|
||||
// TODO Implement animation
|
||||
// TODO On STATE_PORTRAIT_MIDDLE_EXPANDED state, right pane should be pushed out, rather than
|
||||
// squished.
|
||||
|
||||
/**
|
||||
* The "three pane" layout used on tablet.
|
||||
*
|
||||
* It'll encapsulate the behavioral differences between portrait mode and landscape mode.
|
||||
*/
|
||||
public class ThreePaneLayout extends LinearLayout implements View.OnClickListener {
|
||||
|
||||
/** Uninitialized state -- {@link #changePaneState} hasn't been called yet. */
|
||||
private static final int STATE_LEFT_UNINITIALIZED = 0;
|
||||
|
||||
/** Mailbox list + message list */
|
||||
private static final int STATE_LEFT_VISIBLE = 1;
|
||||
|
||||
/** Message view on portrait, + message list on landscape. */
|
||||
private static final int STATE_RIGHT_VISIBLE = 2;
|
||||
|
||||
/** Portrait mode only: message view + expanded message list */
|
||||
private static final int STATE_PORTRAIT_MIDDLE_EXPANDED = 3;
|
||||
|
||||
private int mPaneState = STATE_LEFT_UNINITIALIZED;
|
||||
|
||||
private View mLeftPane;
|
||||
private View mMiddlePane;
|
||||
private View mRightPane;
|
||||
|
||||
// Views used only on portrait
|
||||
private View mCollapser;
|
||||
private View mFoggedGlass;
|
||||
private View mRightWithFog;
|
||||
|
||||
public ThreePaneLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initView();
|
||||
}
|
||||
|
||||
public ThreePaneLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
|
||||
public ThreePaneLayout(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
/** Perform basic initialization */
|
||||
private void initView() {
|
||||
setOrientation(LinearLayout.HORIZONTAL); // Always horizontal
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
getViews();
|
||||
|
||||
if (!isLandscape()) {
|
||||
mFoggedGlass.setOnClickListener(this);
|
||||
mCollapser.setOnClickListener(this);
|
||||
}
|
||||
|
||||
changePaneState(STATE_LEFT_VISIBLE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for views and set to members. {@link #isLandscape} can be used after this method.
|
||||
*/
|
||||
private void getViews() {
|
||||
mLeftPane = findViewById(R.id.left_pane);
|
||||
mMiddlePane = findViewById(R.id.middle_pane);
|
||||
mRightPane = findViewById(R.id.right_pane);
|
||||
|
||||
mCollapser = findViewById(R.id.collapser);
|
||||
if (mCollapser != null) { // If it's there, it's portrait.
|
||||
mFoggedGlass = findViewById(R.id.fogged_glass);
|
||||
mRightWithFog = findViewById(R.id.right_pane_with_fog);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLandscape() {
|
||||
return mCollapser == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
SavedState ss = new SavedState(super.onSaveInstanceState());
|
||||
ss.mPaneState = mPaneState;
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Parcelable state) {
|
||||
// Called after onFinishInflate()
|
||||
SavedState ss = (SavedState) state;
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
changePaneState(ss.mPaneState, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show/hide the right most pane. (i.e. message view)
|
||||
*/
|
||||
public void showRightPane(boolean show) {
|
||||
changePaneState(show ? STATE_RIGHT_VISIBLE : STATE_LEFT_VISIBLE, true);
|
||||
}
|
||||
|
||||
private void changePaneState(int newState, boolean animate) {
|
||||
if (isLandscape() && (newState == STATE_PORTRAIT_MIDDLE_EXPANDED)) {
|
||||
newState = STATE_RIGHT_VISIBLE;
|
||||
}
|
||||
if (newState == mPaneState) {
|
||||
return;
|
||||
}
|
||||
mPaneState = newState;
|
||||
switch (mPaneState) {
|
||||
case STATE_LEFT_VISIBLE:
|
||||
mLeftPane.setVisibility(View.VISIBLE);
|
||||
|
||||
if (isLandscape()) {
|
||||
mMiddlePane.setVisibility(View.VISIBLE);
|
||||
mRightPane.setVisibility(View.GONE);
|
||||
} else { // Portrait
|
||||
mMiddlePane.setVisibility(View.VISIBLE);
|
||||
mCollapser.setVisibility(View.GONE);
|
||||
|
||||
mRightWithFog.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
break;
|
||||
case STATE_RIGHT_VISIBLE:
|
||||
mLeftPane.setVisibility(View.GONE);
|
||||
|
||||
if (isLandscape()) {
|
||||
mMiddlePane.setVisibility(View.VISIBLE);
|
||||
mRightPane.setVisibility(View.VISIBLE);
|
||||
} else { // Portrait
|
||||
mMiddlePane.setVisibility(View.GONE);
|
||||
mCollapser.setVisibility(View.VISIBLE);
|
||||
|
||||
mRightWithFog.setVisibility(View.VISIBLE);
|
||||
mRightPane.setVisibility(View.VISIBLE);
|
||||
mFoggedGlass.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
case STATE_PORTRAIT_MIDDLE_EXPANDED:
|
||||
mLeftPane.setVisibility(View.GONE);
|
||||
|
||||
mMiddlePane.setVisibility(View.VISIBLE);
|
||||
mCollapser.setVisibility(View.VISIBLE);
|
||||
|
||||
mRightWithFog.setVisibility(View.VISIBLE);
|
||||
mRightPane.setVisibility(View.VISIBLE);
|
||||
mFoggedGlass.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ID of the view for the left pane fragment. (i.e. mailbox list)
|
||||
*/
|
||||
public int getLeftPaneId() {
|
||||
return R.id.left_pane;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ID of the view for the middle pane fragment. (i.e. message list)
|
||||
*/
|
||||
public int getMiddlePaneId() {
|
||||
return R.id.middle_pane;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ID of the view for the right pane fragment. (i.e. message view)
|
||||
*/
|
||||
public int getRightPaneId() {
|
||||
return R.id.right_pane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case R.id.collapser:
|
||||
if (isLandscape()) {
|
||||
return; // Shouldn't happen
|
||||
}
|
||||
changePaneState((mPaneState == STATE_RIGHT_VISIBLE)
|
||||
? STATE_PORTRAIT_MIDDLE_EXPANDED
|
||||
: STATE_RIGHT_VISIBLE, true);
|
||||
break;
|
||||
case R.id.fogged_glass:
|
||||
if (isLandscape()) {
|
||||
return; // Shouldn't happen
|
||||
}
|
||||
changePaneState(STATE_RIGHT_VISIBLE, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SavedState extends BaseSavedState {
|
||||
int mPaneState;
|
||||
|
||||
/**
|
||||
* Constructor called from {@link ThreePaneLayout#onSaveInstanceState()}
|
||||
*/
|
||||
SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor called from {@link #CREATOR}
|
||||
*/
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
mPaneState = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeLong(mPaneState);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user