简体   繁体   English

CollapsingToolbarLayout和CollapsingToolbarLayout内的浮动操作按钮位置

[英]CollapsingToolbarLayout and floating action button position inside CollapsingToolbarLayout

I am referring to Cheesesquare app. 我指的是Cheesesquare app。 I have slightly different design requirement at the moment.. 我目前的设计要求略有不同..

Something like this (ignore the part below image and name) 这样的事情(忽略图片和名称下面的部分)

在此输入图像描述

I want floating action button on right bottom corner of circular image and Name of the person below it (which will be CollapsingToolbarLayout title). 我想要圆形图像右下角的浮动操作按钮和它下面的人的名字(这将是CollapsingToolbarLayout标题)。

So far, I am able to achieve this - 到目前为止,我能够做到这一点 -

在此输入图像描述

Problem in this layout is, I am not able to pull down the title below image and I can't re-position floating action button.. 这个布局的问题是,我无法下拉图像下面的标题,我无法重新定位浮动动作按钮..

This is the layout I am using (slightly modified from cheesesquare app) 这是我正在使用的布局(从cheesesquare应用程序略微修改)

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:custom="http://schemas.android.com/apk/res-auto"                                                 
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<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:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="bottom"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        android:fitsSystemWindows="true"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginStart="48dp"
        app:expandedTitleTextAppearance="@style/HeaderTitleStyle"
        app:expandedTitleMarginEnd="64dp">


      <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layout_collapseMode="parallax"
                    android:fitsSystemWindows="true">

          <ImageView
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:id="@+id/imgProfileUserImage"
              android:adjustViewBounds="true"
              android:scaleType="fitXY"
              android:src="@drawable/cheese_1"
              android:alpha="0.35" />


        <Cheesesquare.Utils.CircleImageView
                android:layout_width="180dp"
                android:layout_height="180.0dp"
                android:id="@+id/imgProfileCircleImage"
                android:src="@drawable/cheese_2"
                custom:border="true"
                custom:border_color="#d5d5d5"
                custom:border_width="4dp"
                custom:shadow="true"
                android:layout_gravity="center"
                android:minHeight="80dp"
                android:minWidth="80dp" />



      </FrameLayout>


        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_collapseMode="pin" />

    </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_height="wrap_content"
              android:id="@+id/uploadPhotoButton"
              android:layout_width="wrap_content"
              app:layout_anchor="@id/appbar"
              app:layout_anchorGravity="bottom|right|end"
              android:src="@drawable/ic_discuss"
              android:layout_margin="@dimen/fab_margin"
              android:clickable="true"/>

Little help would be appreciated :-) 很少的帮助将不胜感激:-)

Update 更新

  1. I managed to center the text and make it look like the required user interface.. The only thing remaining is to set the circular ImageView as an anchor of FAB and then make it disappear as soon as CollapsingToolbarLayout goes off.. 我设法使文本居中并使其看起来像所需的用户界面。唯一剩下的就是将圆形ImageView设置为FAB的锚点,然后在CollapsingToolbarLayout关闭后立即消失。

在此输入图像描述

Question 1. Hide anchored view on collapsing the associated view. 问题1.在折叠关联视图时隐藏锚定视图。

As far as i noticed, an anchor attribute really has some weird influence on possibility of the view to be hidden on collapsing. 据我所知,一个锚属性确实对视图隐藏在折叠上的可能性有一些奇怪的影响。 So well-tried solution is to perform it programmatically: 如此经过良好尝试的解决方案是以编程方式执行它:

appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
        /**
         * verticalOffset changes in diapason
         * from 0 - appBar is fully unwrapped
         * to -appBarLayout's height - appBar is totally collapsed
         * so in example we hide FAB when user folds half of the appBarLayout
         */
        if (appBarLayout.getHeight() / 2 < -verticalOffset) {
            fab.setVisibility(View.GONE);
        } else {
            fab.setVisibility(View.VISIBLE);
        }
    }
});

Question 2. How to bind view directly to border of circle image. 问题2.如何将视图直接绑定到圆形图像的边框。

Unfortunately "CircleView" is an ordinary view with the usual rectangular shape. 不幸的是,“CircleView”是具有通常矩形形状的普通视图。 You can easily verify this by setting it's background parameter. 您可以通过设置它的背景参数轻松验证这一点。

So in your case FAB is anchored to view's corner but not the point at circular border. 因此,在您的情况下,FAB锚定到视图的角落,但不是圆形边界处的点。 The solution I can suggest is as follows: 我建议的解决方案如下:

  1. Put the FAB into wrapper layout 将FAB放入包装布局
  2. Apply to that wrapper attributes relevant to the anchor regulations (and remove these attributes from the FAB) 应用与锚规则相关的包装器属性(并从FAB中删除这些属性)
  3. Correct the FAB position by setting the layout padding. 通过设置布局填充来更正FAB位置。 Value for padding is (0.2928 * CircleImage.width) 填充值为(0.2928 * CircleImage.width)

Here we use the wrapper layout in order to avoid potential issues with relocation of anchored view through its margins. 在这里,我们使用包装器布局,以避免通过其边距重新定位锚定视图的潜在问题。

Value 0.2928 is a coefficient to calculate the distance from square's corner to the closest point of circle which is inscribed to it. 值0.2928是计算从正方形角到最接近圆的点的距离的系数。

After all this magic FAB should turn into something like this (assume that we bind the FAB to the circle image with width == 180dp as in the question): 毕竟这个神奇的FAB应该变成这样的东西(假设我们将FAB绑定到宽度为== 180dp的圆形图像,如问题所示):

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="53dp"
    android:paddingRight="53dp"
    app:layout_anchor="@+id/imgProfileCircleImage"
    app:layout_anchorGravity="bottom|right">

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/uploadPhotoButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:src="@drawable/ic_discuss" />
</FrameLayout>

Edited 编辑

The second solution can be improved to avoid manual calculation of paddings. 可以改进第二解决方案以避免手动计算填充。 We just need the custom layout which can perform them itself: 我们只需要可以自己执行的自定义布局:

public class CustomFrameLayout extends FrameLayout {
    public CustomFrameLayout(Context context) {
        super(context);
    }

    public CustomFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupPaddings(context, attrs);
    }

    public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setupPaddings(context, attrs);
    }

    private void setupPaddings(Context context, AttributeSet attrs) {
        int diameter = 0;
        TypedArray attrArray = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.FabLayout,
                0, 0);
        try {
            diameter = attrArray.getInteger(R.styleable.FabLayout_anchor_diameter, 0);
        } finally {
            attrArray.recycle();
        }

        int padding = (int) Math.round((double) diameter * (1d - 1d / (Math.sqrt(2d)))); // in dips
        int paddingPx = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, padding, getResources().getDisplayMetrics()));

        String xmlAnchorGravity = attrs.getAttributeValue("http://schemas.android.com/apk/res-auto", "layout_anchorGravity");
        int gravity = Integer.parseInt(xmlAnchorGravity.substring(2), 16);

        int top = ((gravity & 0x30) == 0x30) ? 1 : 0;
        int bottom = ((gravity & 0x50) == 0x50) ? 1 : 0;
        int left = ((gravity & 0x03) == 0x03) ? 1 : 0;
        int right = ((gravity & 0x05) == 0x05) ? 1 : 0;

        setPadding(left * paddingPx,
                top * paddingPx,
                right * paddingPx,
                bottom * paddingPx);
    }
}

And declare additional attribute for it in declare-styleable: 并在declare-styleable中声明它的附加属性:

<declare-styleable name="FabLayout">
    <attr name="anchor_diameter" format="integer" />
</declare-styleable>

And after that we are able to replace this: 之后我们可以替换这个:

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingBottom="53dp"
    android:paddingRight="53dp"
    ...

with more suitable form: 更合适的形式:

<com.example.CustomFrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:anchor_diameter="180"
    ...

The issue you are having is that the CircleImageView is a circle inside a square box, when you set the FAB to anchor to the CircleImageView it anchors to the corner of the bounding box and not the actual ImageView itself. 您遇到的问题是CircleImageView是一个方框内的圆圈,当您将FAB设置为锚定到CircleImageView时,它会锚定到边界框的角落而不是实际的ImageView本身。

Normally you could correct this by adding a margin to the right and bottom to move the FAB into position but it seems there's a bug in the Design Support Library that causes margins to be ignored. 通常,您可以通过在右侧和底部添加边距来将FAB移动到位来纠正此问题,但似乎设计支持库中存在导致边距被忽略的错误。

Here's another SO issue discussing it further. 这是另一个SO问题 ,进一步讨论它。

Here's an issue that has been logged with Google. 这是Google记录的问题

The issue has been assigned to someone on the Android team so hopefully it gets fixed in a later release. 该问题已分配给Android团队中的某个人,因此希望它在以后的版本中得到修复。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM