CoordinatorLayout的基本使用

1. 概述


  CoordinatorLayout顾名思义,协调者布局。所谓的协调者布局,它主要是协调谁,协调啥呢?我相信大家在学这个布局时,都会思考这两个问题。其实说的简单点,协调者布局主要协调child之间的联动。请注意我的措辞,child之间的联动。
  可能有的同学对联动还是有点陌生,我简单的举一个例子,比如说,我们在滑动一个RecyclerView,存在一个View需要在RecyclerView滑动时做相应的动作,例如,位移变化,缩放变化等等。我相信这种场景还是非常常见的吧。这种场景就可以称之为child之间联动。
  而CoordinatorLayout是怎么进行协调呢?主要依靠一个插件--Behavior。在CoordinatorLayout内部,每个child都必须带一个Behavior(其实不携带也行,不携带就不能被协调),CoordinatorLayout就根据每个child所携带的Behavior信息进行协调。
  这里还需要提一句的是,Behavior不仅仅协助联动,而且还是接管了child的三大流程,有点类似于RecyclerViewLayoutManager
  而Behavior是怎么进行协助联动呢?这就涉及到嵌套滑动的相关知识,总的来说,Behavior包括整个CoordinatorLayout体系就是对嵌套滑动的应用和实现。所以,我们便知道了,嵌套滑动到底有多么重要了。
  本文主要介绍CoordinatorLayout的基本使用,主要是介绍CoordinatorLayoutAppBarLayout的搭配使用。

2. AppBarLayout

  如果我们想要实现折叠的ActionBar效果,在CoordinatorLayout中,AppBarLayout绝对是作为首选的控件。
  在正式介绍AppBarLayout的使用时,我们先来看看几个Flag,这几个Flag在AppBarLayout里面非常的重要。

名称作用
SCROLL_FLAG_NO_SCROLL0x0设置这个flag,将表示该View不能被滑动。也就是说不参与联动。
SCROLL_FLAG_SCROLL0x01设置这个Flag,表示该View参与联动。具体效果需要跟其他Flag组合。
SCROLL_FLAG_EXIT_UNTIL_COLLAPSED0x02设置这个Flag,表示当View被推出屏幕时,会跟着滑动,直到折叠到View的最小高度;同时只有在其他View(比如说RecyclerView)滑动到顶部才会展开。
SCROLL_FLAG_ENTER_ALWAYS0x02设置这个Flag,不管是View是滑出屏幕还是滑进屏幕,该View都能立即响应滑动事件,跟随滑动。比如说,如果该View是折叠的,当RecyclerView向下滑动时,该View随时都能跟随展开;反之亦然。
SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED0x04SCROLL_FLAG_ENTER_ALWAYS的基础上,该Flag增加了折叠到固定高度的限制。在View下拉过程中,首先会将该View显示minHeight的高度,RecyclerView在继续下拉(这里以RecyclerView为例)。注意,该Flag在SCROLL_FLAG_ENTER_ALWAYS前提下生效。
SCROLL_FLAG_SNAP0x08该Flag表示View拥有吸附功能。比如说,当前滑动停止,View离底部更近,那么就会折叠;反之则会展开。

  这几个Flag非常的简单,我们来看看具体的使用,先来看看布局文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <View
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#5FF"
            app:layout_scrollFlags="scroll|enterAlwaysCollapsed" />
        <View
            android:background="#FF00FF"
            android:layout_width="match_parent"
            android:layout_height="50dp"/>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

这里需要几点,如下:

  1. 我在AppBarLayout里面放了两个View,其中一个设置scrollFlags,一个没有设置。没有设置的是不会折叠的。
  2. 在这里,AppBarLayout并没有设置Behavior,而RecyclerView却设置了的。我统一的解释一下,在CoordinatorLayout内部,理论上每个View必须携带一个Behavior,而这里AppBarLayout没有携带是因为它本身就有,所以不需要申明(在后面,我们会看到几种设置Behavior的方式,这里买一个关子。)

  然后,我们来看看效果:

 

  这里,我不再介绍其他Flag的效果,有兴趣可以尝试一下。

3. CollapsingToolbarLayout

  接下来,我们再来看一下CollapsingToolbarLayoutCollapsingToolbarLayout主要是实现折叠布局的,我们来看看是怎么使用的。首先,我们来看看CollapsingToolbarLayout的几个Flag:

名称作用
COLLAPSE_MODE_OFF0默认值,表示View不会有任何属性
COLLAPSE_MODE_PIN1CollapsingToolbarLayout完全收缩之后,设置该Flag的View会保留在屏幕当中。
COLLAPSE_MODE_PARALLAX2设置该Flag的View会跟内容滚动,可以通过setParallaxMultiplier方法来设置视图差比率,其中0表示毫无视图差,完全跟内容滚动同步;1表示View完全不动。默认的视图差为0.5。

  接下来我们看一个Demo:

<androidx.coordinatorlayout.widget.CoordinatorLayout 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">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="300dp">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/demo"
                app:layout_collapseMode="parallax" />

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:background="#5FF"
                app:layout_collapseMode="pin" />
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

使用CollapsingToolbarLayout时,我们需要注意的是:CollapsingToolbarLayout需要作为AppBarLayout子View。然后我们来看看相关的效果:

4. 总结

  本文主要介绍CoordinatorLayout的基本使用,还是非常简单的,但是我们从上面的代码看出,好像根本就没有介绍它。CoordinatorLayout作为协调者,肯定是非常重要的,具体介绍在后续的文章会详细的分析。在这里先对本文做一个简单的总结。

  1. 使用AppBarLayout时,我们需要注意4种flag的不同点。
  2. CollapsingToolbarLayout需要作为AppBarLayout的子View才会有效,同时还需要注意它的3种flag。

  如果不出意外的话,下一篇文章我们将分析RecyclerViewAppBarLayout的联动。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以为您提供一些实现步骤和代码示例。 1. 首先,您需要创建一个新的Android项目,并添加以下依赖项: ```java dependencies { implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.fragment:fragment:1.3.0' implementation 'com.google.android.material:material:1.3.0' } ``` 2. 接下来,创建一个MainActivity和一个布局文件activity_main.xml。在布局文件中,添加一个FloatingActionButton和一个FrameLayout,用于显示Fragment。 ```xml <androidx.coordinatorlayout.widget.CoordinatorLayout android:id="@+id/coordinator_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="match_parent" /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="16dp" android:src="@drawable/ic_add" app:backgroundTint="@color/colorPrimaryDark" /> </androidx.coordinatorlayout.widget.CoordinatorLayout> ``` 3. 创建一个Fragment用于显示记账的列表,并添加一个布局文件fragment_list.xml。在布局文件中,添加一个RecyclerView。 ```xml <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 4. 创建一个类来表示记账的条目: ```java public class Expense { private String title; private double amount; private Date date; public Expense(String title, double amount, Date date) { this.title = title; this.amount = amount; this.date = date; } public String getTitle() { return title; } public double getAmount() { return amount; } public Date getDate() { return date; } } ``` 5. 创建一个ExpenseAdapter类来管理RecyclerView中的数据项。这个类需要继承RecyclerView.Adapter,并实现一些必要的方法。 ```java public class ExpenseAdapter extends RecyclerView.Adapter<ExpenseAdapter.ViewHolder> { private List<Expense> expenses; public ExpenseAdapter(List<Expense> expenses) { this.expenses = expenses; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item_expense, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Expense expense = expenses.get(position); holder.titleTextView.setText(expense.getTitle()); holder.amountTextView.setText(String.format(Locale.getDefault(), "%.2f", expense.getAmount())); holder.dateTextView.setText(new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(expense.getDate())); } @Override public int getItemCount() { return expenses.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { public TextView titleTextView; public TextView amountTextView; public TextView dateTextView; public ViewHolder(View itemView) { super(itemView); titleTextView = itemView.findViewById(R.id.text_view_title); amountTextView = itemView.findViewById(R.id.text_view_amount); dateTextView = itemView.findViewById(R.id.text_view_date); } } } ``` 6. 在fragment_list.xml中,添加一个list_item_expense.xml布局文件,用于显示Expense对象的属性。 ```xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp"> <TextView android:id="@+id/text_view_title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Title" android:textAppearance="?android:textAppearanceMedium" /> <TextView android:id="@+id/text_view_amount" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Amount" android:textAppearance="?android:textAppearanceMedium" /> <TextView android:id="@+id/text_view_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Date" android:textAppearance="?android:textAppearanceMedium" /> </LinearLayout> ``` 7. 在MainActivity中,实现FloatingActionButton的点击事件,并显示Fragment。 ```java public class MainActivity extends AppCompatActivity { private FloatingActionButton fabAdd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fabAdd = findViewById(R.id.fab_add); fabAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { showAddExpenseFragment(); } }); showExpenseListFragment(); } private void showExpenseListFragment() { FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.fragment_container, new ExpenseListFragment()); transaction.commit(); } private void showAddExpenseFragment() { FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.fragment_container, new AddExpenseFragment()); transaction.addToBackStack(null); transaction.commit(); } } ``` 8. 创建一个ExpenseListFragment类来显示Expense列表。 ```java public class ExpenseListFragment extends Fragment { private RecyclerView recyclerView; private ExpenseAdapter adapter; private List<Expense> expenses; public ExpenseListFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); expenses = new ArrayList<>(); expenses.add(new Expense("Food", 30.0, new Date())); expenses.add(new Expense("Transportation", 10.0, new Date())); expenses.add(new Expense("Entertainment", 50.0, new Date())); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_list, container, false); recyclerView = view.findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); adapter = new ExpenseAdapter(expenses); recyclerView.setAdapter(adapter); return view; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.menu_expense_list, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_add: ((MainActivity) getActivity()).showAddExpenseFragment(); return true; default: return super.onOptionsItemSelected(item); } } } ``` 9. 创建一个AddExpenseFragment来添加新的Expense条目。 ```java public class AddExpenseFragment extends Fragment { public AddExpenseFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_add_expense, container, false); //TODO: Add UI elements and logic for adding a new expense return view; } } ``` 10. 最后,您可以使用Android本地数据库来保存Expense对象。这里只是一个简单的示例: ```java public void addExpense(Expense expense) { SQLiteDatabase db = getWritableDatabase(); ContentValues values = new ContentValues(); values.put("title", expense.getTitle()); values.put("amount", expense.getAmount()); values.put("date", expense.getDate().getTime()); db.insert("expenses", null, values); db.close(); } public List<Expense> getExpenses() { SQLiteDatabase db = getReadableDatabase(); Cursor cursor = db.query("expenses", null, null, null, null, null, null); List<Expense> expenses = new ArrayList<>(); while (cursor.moveToNext()) { String title = cursor.getString(cursor.getColumnIndex("title")); double amount = cursor.getDouble(cursor.getColumnIndex("amount")); long dateMillis = cursor.getLong(cursor.getColumnIndex("date")); expenses.add(new Expense(title, amount, new Date(dateMillis))); } cursor.close(); db.close(); return expenses; } ``` 以上是一个简单的记账本应用程序的实现步骤和示例代码。当然,这只是一个简单的示例,您可以在此基础上进一步扩展和改进您的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金戈鐡馬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值