CollapsingToolbarLayout и положение кнопки плавающего действия внутри CollapsingToolbarLayout

Я имею в виду приложение Cheesesquare. На данный момент у меня есть немного разные требования к дизайну.

Что-то вроде этого (игнорируйте часть ниже изображения и имени)

Введите описание изображения здесь

Я хочу кнопку плавающего действия в правом нижнем углу кругового изображения и имя лица ниже него (это будет CollapsingToolbarLayout название).

Пока я могу добиться этого –

Введите описание изображения здесь

Проблема в этом макете заключается в том, что я не могу вытащить заголовок под изображением, и я не могу переопределить плавающее действие.

Это макет, который я использую (слегка измененный из приложения 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"/> 

Маленькая помощь была бы оценена 🙂

Обновить

  1. Мне удалось центрировать текст и сделать его похожим на требуемый пользовательский интерфейс. Остается только установить круговой ImageView в качестве якоря FAB, а затем заставить его исчезнуть, как только CollapsingToolbarLayout отключится.

Введите описание изображения здесь

Вопрос 1. Скрыть привязанный вид на сворачивание связанного представления.

Насколько я заметил, атрибут привязки действительно имеет какое-то странное влияние на возможность скрытия представления при свертывании. Настолько хорошо зарекомендовавшее себя решение – выполнить его программно:

 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); } } }); 

Вопрос 2. Как привязать вид непосредственно к границе круга.

К сожалению, «CircleView» – это обычный вид с обычной прямоугольной формой. Вы можете легко проверить это, установив его фоновый параметр.

Поэтому в вашем случае FAB привязан к углу обзора, но не к точке на круговой границе. Решение, которое я могу предложить, следующее:

  1. Поместите FAB в макет оболочки
  2. Применитесь к атрибутам обертки, относящимся к правилам привязки (и удалите эти атрибуты из FAB)
  3. Исправьте позицию FAB, установив прокладку макета. Значение для заполнения – (0.2928 * CircleImage.width)

Здесь мы используем макет оболочки, чтобы избежать потенциальных проблем с перемещением привязанного представления через его поля.

Значение 0.2928 – это коэффициент для вычисления расстояния от угла квадрата до ближайшей точки круга, который вписан в него.

После этого волшебный 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> 

отредактированный

Второе решение можно улучшить, чтобы избежать ручного расчета прокладок. Нам просто нужен пользовательский макет, который может выполнять их сам:

 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); } } 

И объявить дополнительный атрибут для него в declare-styleable:

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

И после этого мы можем заменить это:

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

С более подходящей формой:

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

Проблема, с которой вы сталкиваетесь, заключается в том, что CircleImageView представляет собой круг внутри квадратного поля, когда вы устанавливаете FAB для привязки к CircleImageView, он привязывается к углу ограничительной рамки, а не к самому самому ImageView.

Обычно вы можете исправить это, добавив маркер справа и снизу, чтобы переместить FAB в нужное положение, но, похоже, в библиотеке поддержки дизайна есть ошибка, из-за которой поля игнорируются.

Вот еще одна проблема, обсуждающая ее далее.

Вот проблема , связанная с Google.

Проблема была назначена кому-то из команды Android, поэтому, надеюсь, она будет исправлена ​​в более позднем выпуске.

Intereting Posts
Можно ли нарисовать жизненный цикл Фрагмента и его родительского FragmentActivity? Сбой при применении панели инструментов Как использовать PubNub для публикации отзыва, чтобы узнать, какое сообщение следует публиковать в случае ошибки Ошибка: ожидаемый получатель типа com.MyApp.Main, но получил java.lang.Class <com.MyApp.Main> Android org.xmlpull.v1.XmlPullParserException при анализе XML Android: как развернуть и свернуть размер экрана в RecyclerView Expandablelistview расширяет simplecursoradapter для заполнения из sqlite Невозможно создать экземпляр активности. ComponentInfo не может создавать экземпляр класса Показать мягкую клавиатуру в AlertDialog с помощью WebView внутри (Android) Android против Linux для встроенного приложения для сенсорного экрана Как показать аудиофайлы в списке в Android? Получение APP_ID для Facebook? «Id не может быть нулевым» – GoogleJsonResponseException 400 Bad Request Новый список приложений в стиле «Входящие» для Android с прорисовкой влево и вправо Диалоговое окно Android Image / Popup