背景
我的任务是创建一个UI,其行为类似于Google Maps显示找到结果的底页的方式。
它有三个不同的阶段:
以下是我在谷歌地图上讨论的内容:
问题所在
问题是,底部的工作表还不是设计库的一部分(尽管它是被请求的,)。
不仅如此,UI看起来相当复杂,需要在多个阶段处理工具栏。
我尝试过的
我已经为底层表单()找到了一个很好的(足够的)库,并将内容添加到它的片段样本中,以获得与材料设计样本(如)上显示的视图大致相同的视图,从而拥有一个将处理阶段2+3的CollapsingToolbarLayout。
在我正在制作的应用程序中,我还必须在你滚动时移动一个图标,但我认为如果我成功地完成了其余的操作,这应该很容易。代码如下:
###fragment_my.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<ImageView
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="24dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Info"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Friends"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/card_margin"
android:layout_marginLeft="@dimen/card_margin"
android:layout_marginRight="@dimen/card_margin">
<LinearLayout
style="@style/Widget.CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Related"
android:textAppearance="@style/TextAppearance.AppCompat.Title"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cheese_ipsum"/>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
android:clickable="true"
android:src="@android:drawable/ic_menu_send"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>
###MyFragment.java
public class MyFragment extends BottomSheetFragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_my, container, false);
view.setMinimumHeight(getResources().getDisplayMetrics().heightPixels);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) view.findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("AAA");
final Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
final AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(toolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
NavUtils.navigateUpFromSameTask(getActivity());
}
});
final ImageView imageView = (ImageView) view.findViewById(R.id.backdrop);
Glide.with(this).load(R.drawable.cheese_1).centerCrop().into(imageView);
return view;
}
}
###BottomSheetFragmentActivity.java
public final class BottomSheetFragmentActivity extends AppCompatActivity {
protected BottomSheetLayout bottomSheetLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom_sheet_fragment);
bottomSheetLayout = (BottomSheetLayout) findViewById(R.id.bottomsheet);
findViewById(R.id.bottomsheet_fragment_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyFragment().show(getSupportFragmentManager(), R.id.bottomsheet);
}
});
bottomSheetLayout.setShouldDimContentView(false);
bottomSheetLayout.setPeekOnDismiss(true);
bottomSheetLayout.setPeekSheetTranslation(200);
bottomSheetLayout.setInterceptContentTouch(false);
bottomSheetLayout.setDefaultViewTransformer(new BaseViewTransformer() {
@Override
public void transformView(final float translation, final float maxTranslation, final float peekedTranslation, final BottomSheetLayout parent, final View view) {
Log.d("AppLog", "translation:" + translation + " maxTranslation:" + maxTranslation + " peekedTranslation:" + peekedTranslation);
}
});
}
}
它几乎工作得很好。唯一的问题是从#3到#2的转换:
问题是
代码有什么问题?为了实现所需的行为,我可以做些什么?
发布于 2015-12-09 18:36:37
注释:阅读底部的编辑
好吧,我已经找到了一种方法,但我必须更改多个类的代码,以便底部的表单可以知道appBarLayout的状态(展开或未展开),并忽略向上滚动,以防它未展开:
BottomSheetLayout.java
新增字段:
private AppBarLayout mAppBarLayout;
private OnOffsetChangedListener mOnOffsetChangedListener;
private int mAppBarLayoutOffset;
init() -添加了这个:
mOnOffsetChangedListener = new OnOffsetChangedListener() {
@Override
public void onOffsetChanged(final AppBarLayout appBarLayout, final int verticalOffset) {
mAppBarLayoutOffset = verticalOffset;
}
};
增加设置appBarLayout的功能:
public void setAppBarLayout(final AppBarLayout appBarLayout) {
if (mAppBarLayout == appBarLayout)
return;
if (mAppBarLayout != null)
mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);
mAppBarLayout = appBarLayout;
mAppBarLayout.addOnOffsetChangedListener(mOnOffsetChangedListener);
}
onDetachedFromWindow() -添加了以下内容:
if (mAppBarLayout != null)
mAppBarLayout.removeOnOffsetChangedListener(mOnOffsetChangedListener);
onTouchEvent() -添加了以下内容:
...
if (bottomSheetOwnsTouch) {
if (state == State.EXPANDED && scrollingDown && mAppBarLayout != null && mAppBarLayoutOffset != 0) {
event.offsetLocation(0, sheetTranslation - getHeight());
getSheetView().dispatchTouchEvent(event);
return true;
}
...
这些是主要的变化。现在让我们来看看是什么设置了它们:
MyFragment.java
onCreateView() -添加了以下内容:
mBottomSheetLayout.setAppBarLayout((AppBarLayout) view.findViewById(R.id.appbar));
我还添加了这个函数:
public void setBottomSheetLayout(final BottomSheetLayout bottomSheetLayout) {
mBottomSheetLayout = bottomSheetLayout;
}
现在,这是该活动告诉片段有关appBarLayout的方式:
final MyFragment myFragment = new MyFragment();
myFragment.setBottomSheetLayout(bottomSheetLayout);
myFragment.show(getSupportFragmentManager(), R.id.bottomsheet);
该项目现已在GitHub上提供:
https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet
我希望它没有任何bug。
遗憾的是,这个解决方案有错误,所以我不会将这个答案标记为正确的:
如果有人能帮上忙,请帮忙。
对于第一个问题,我尝试了添加一个修复,当底部的页面还没有偷看时,我将可见性设置为不可见,但它并不总是有效的,特别是当键盘显示的时候。
对于第一个问题,我已经找到了如何修复它,只需用你想要使用的任何视图(我使用FrameLayout)包装(在“fragment_my.xml”中) CoordinatorLayout,并在其中放入一个完整大小的视图(我只放了" view "),如下所示:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--This full sized view, together with the FrameLayout above, are used to handle some weird UI issues on pre-Android-6 -->
<View
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<...CollapsingToolbarLayout
...
当我把CoordinatorLayout作为它的视图时,它可能把bottomSheet搞混了。我已经更新了项目,但是,如果有更好的解决方案,我想知道它。
最近几个月,谷歌发布了自己的bottomSheet类,但我发现它有很多问题,所以我甚至不能尝试它。
发布于 2016-05-25 12:57:09
大更新
因为有4到5个关于同一主题的问题,但有不同的要求,我试图回答所有这些问题,但一个不礼貌的管理员删除/关闭了它们,让我为每个问题创建了一个工单,并对它们进行了更改,以避免“复制-粘贴”。我会给你一个到full answer的链接,在那里你可以找到关于如何像谷歌地图一样获得完整行为的所有解释。
回答你的问题
如何模仿谷歌地图的底页三阶段行为?
使用支持库23.x.x+,您可以通过以下步骤修改默认的BottomSheetBehavior
,添加更多的stat:
Java创建一个类并从CoordinatorLayout.Behavior<V>
扩展它
BottomSheetBehavior
文件复制粘贴到新文件中。clampViewPositionVertical
方法:@Override public int (View child,int top,int dy) { return constrain(clampViewPositionVertical,mMinOffset,mHideable?mParentHeight : mMaxOffset);} int约束( int数量,int低,int高){返回量<低?低:(数量>高?high :数量);}
public static final int STATE_ANCHOR_POINT = X;
onLayoutChild
、onStopNestedScroll
、BottomSheetBehavior<V> from(V view)
和setState
(可选)我将添加这些修改后的方法和一个link to the example project。
,下面是它看起来像的样子
发布于 2016-05-04 12:03:54
你试过了吗?http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1这里说我们可以只指定一个底部页面的布局行为。
更新:
基本上,链接状态是-
通过将BottomSheetBehavior附加到CoordinatorLayout的子视图(即,添加app:layout_behavior="android.support.design.widget.BottomSheetBehavior"),),您将自动获得适当的触摸检测,以便在五种状态之间转换:
STATE_COLLAPSED: this collapsed state is the default and shows just a portion of the layout along the bottom. The height can be controlled with the app:behavior_peekHeight attribute (defaults to 0)
STATE_DRAGGING: the intermediate state while the user is directly dragging the bottom sheet up or down
STATE_SETTLING: that brief time between when the View is released and settling into its final position
STATE_EXPANDED: the fully expanded state of the bottom sheet, where either the whole bottom sheet is visible (if its height is less than the containing CoordinatorLayout) or the entire CoordinatorLayout is filled
STATE_HIDDEN: disabled by default (and enabled with the app:behavior_hideable attribute), enabling this allows users to swipe down on the bottom sheet to completely hide the bottom sheet
Keep in mind that scrolling containers in your bottom sheet must support nested scrolling (for example, NestedScrollView, RecyclerView, or ListView/ScrollView on API 21+).
如果你想接收状态改变的回调,你可以添加一个BottomSheetCallback:
// The View with the BottomSheetBehavior
View bottomSheet = coordinatorLayout.findViewById(R.id.bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
behavior.setBottomSheetCallback(new BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
// React to state change
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// React to dragging events
}
});
虽然BottomSheetBehavior捕获了持久的底层表单用例,但此版本还提供了一个BottomSheetDialog和BottomSheetDialogFragment来填充模态底层表单用例。只需将AppCompatDialog或AppCompatDialogFragment替换为对应的底部工作表,即可将对话框样式化为底部工作表。
https://stackoverflow.com/questions/34160423
复制相似问题