fundo
Fui designado para fazer uma IU que se comporta de forma semelhante a como o Google Maps mostra uma folha de baixo para um resultado encontrado.
Possui três fases diferentes:
- Conteúdo inferior. A área superior ainda pode ser tocada e não rolará nada na parte inferior
- Conteúdo em tela cheia, enquanto a área superior possui um grande cabeçalho.
- Conteúdo em tela cheia, enquanto a área superior possui apenas a barra de ferramentas.
Aqui está o que estou falando no Google Maps:
O problema
O fato é que a folha de baixo ainda não faz parte da biblioteca de design (embora tenha sido solicitada, aqui ).
Não apenas isso, mas a IU parece bastante complexa e precisa ser tratada com a barra de ferramentas em várias fases.
O que eu tentei
Eu encontrei uma biblioteca boa (o suficiente) para a folha de baixo ( aqui ), e adicionei conteúdo à sua amostra de fragmento, para ter aproximadamente as mesmas visualizações mostradas nas amostras de material design (como aqui ), para ter um CollapsingToolbarLayout que cuidará das fases 2 + 3.
No aplicativo que estou fazendo, também preciso mover um ícone conforme você rola, mas acho que, se tiver sucesso com o resto, será fácil. Aqui está o código:
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);
}
});
}
}
Quase funciona bem. O único problema é a transição do n.º 3 para o n.º 2:
A questão
O que há de errado com o código? O que posso fazer para alcançar o comportamento necessário?
fonte
CoordinatorLayout
na 2ª tela?Respostas:
Nota : Leia as edições na parte inferior
OK, encontrei uma maneira de fazer isso, mas tive que alterar o código de várias classes, para que a folha inferior soubesse do estado do appBarLayout (expandido ou não) e ignore a rolagem para cima, caso seja não expandido:
BottomSheetLayout.java
Campos adicionados:
init () - adicionado isto:
Adicionada função para definir o appBarLayout:
onDetachedFromWindow () - adicionado este:
onTouchEvent () - adicionado este:
Essas foram as principais mudanças. Agora, para saber o que os define:
MyFragment.java
onCreateView () - adicionado este:
Eu também adicionei esta função:
Agora é assim que a atividade informa o fragmento sobre o appBarLayout:
O projeto agora está disponível no GitHub:
https://github.com/AndroidDeveloperLB/ThreePhasesBottomSheet
Espero que não tenha nenhum bug.
A solução tem bugs, infelizmente, então não marcarei esta resposta como a correta:
Se alguém puder ajudar com isso, por favor, ajude.
Para o problema nº 1, tentei adicionar uma correção definindo a visibilidade como INVISÍVEL quando a folha inferior ainda não foi exibida, mas nem sempre funciona, especialmente se um teclado for mostrado.
Para o problema nº 1, descobri como corrigi-lo, apenas envolvendo (em "fragment_my.xml") o CoordinatorLayout com qualquer visualização que você deseja usar (usei FrameLayout) e também coloque uma visualização em tamanho real em (acabei de colocar "Exibir"), como tal:
Provavelmente confundiu bottomSheet quando eu tinha o CoordinatorLayout sendo sua visualização. Atualizei o projeto, mas ainda assim, se houver alguma maneira de ter uma solução mais legal, gostaria de saber.
Nos últimos meses, o Google publicou sua própria classe bottomSheet, mas como descobri que ela tem muitos problemas, não posso nem experimentar.
fonte
BIG UPDATE
Porque havia cerca de 4 ou 5 perguntas sobre o mesmo tópico, MAS com requisitos DIFERENTES, e eu tentei responder a todas elas, mas um administrador não educado excluiu / fechou, me fazendo criar um tíquete para cada uma e mudá-las para evite "copiar e colar" Vou deixar você um link para a resposta completa em que você pode encontrar todas as explicações sobre como obter um comportamento completo como o Google Maps.
Respondendo sua pergunta
Com a biblioteca de suporte 23.x.x + você pode fazer isso modificando o padrão
BottomSheetBehavior
, adicionando mais uma estatística com as seguintes etapas:CoordinatorLayout.Behavior<V>
BottomSheetBehavior
arquivo padrão para o novo.Modifique o método
clampViewPositionVertical
com o seguinte código:Adicione um novo estado:
Modificar os próximos métodos:
onLayoutChild
,onStopNestedScroll
,BottomSheetBehavior<V> from(V view)
esetState
(opcional)Vou adicionar esses métodos modificados e um link para o projeto de exemplo .
E é assim que fica:
fonte
CoordinatorLayout
emactivity_main.xml
. Acho que você tem uma boa experiência com layout de coordenador, caso contrário, dê uma olhada neste link que encontreiVocê tentou isso? http://android-developers.blogspot.in/2016/02/android-support-library-232.html?m=1 Aqui diz que podemos apenas especificar um comportamento de layout de folha inferior.
ATUALIZAR:
Basicamente, o link indica
Ao anexar um BottomSheetBehavior a uma View filho de um CoordinatorLayout (ou seja, adicionando app: layout_behavior = "android.support.design.widget.BottomSheetBehavior"), você obterá automaticamente a detecção de toque apropriada para fazer a transição entre cinco estados:
Se quiser receber retornos de chamada de mudanças de estado, você pode adicionar um BottomSheetCallback:
Enquanto BottomSheetBehavior captura o caso de uso persistente da folha inferior, esta versão também fornece um BottomSheetDialog e BottomSheetDialogFragment para preencher o caso de uso modal das folhas inferiores. Basta substituir AppCompatDialog ou AppCompatDialogFragment por seus equivalentes de folha inferior para ter seu diálogo estilizado como uma folha inferior.
fonte
Eu também tive que implementar uma visão semelhante a como o Google Maps mostra uma folha de baixo para um resultado encontrado.
Veja como o meu se parece:
No início, eu defini uma folha inferior com um cabeçalho e conteúdo rolável, mas o layout_height não pareceu envolver o conteúdo nem do cabeçalho nem do conteúdo rolável, apesar de especificar
wrap_content
.Esse problema foi embora quando eu usei em
LinearLayout
vez deConstraintLayout
para oCoordinatorLayout
layout filho de (e para seus filhos).activity_main.xml
MainActivity.java
app / build.gradle
fonte