📜  Fab 到 CircularRevealFrameLayout 示例 - Java (1)

📅  最后修改于: 2023-12-03 15:00:41.313000             🧑  作者: Mango

Fab 到 CircularRevealFrameLayout 示例 - Java

本示例演示如何使用 FloatingActionButton (Fab) 将一个菜单展开到 CircularRevealFrameLayout 中。

前提条件

在开始本示例之前,您应该已经熟悉以下内容:

  • 基本的 Java 语法
  • Android 开发基础知识
  • 如何创建一个新的 Android 项目
实现步骤
添加依赖项

将以下依赖项添加到您的 build.gradle 文件中:

implementation 'com.android.support:design:28.0.0'
创建布局

在布局文件中添加以下代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/content_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:padding="24dp">

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/fab_margin_bottom"
        android:layout_marginEnd="@dimen/fab_margin_end"
        android:src="@drawable/ic_add_white_24dp"
        app:backgroundTint="@color/colorPrimary"
        app:fabSize="normal" />

    <android.support.constraint.ConstraintLayout
        android:id="@+id/hidden_content_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible">

        <!-- 折叠的菜单内容在这里添加 -->

    </android.support.constraint.ConstraintLayout>

    <View
        android:id="@+id/overlay"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black"
        android:alpha="0"
        android:onClick="@{() -> viewModel.hideMenu()}"
        android:visibility="@{viewModel.showMenu ? View.VISIBLE : View.GONE}" />

</android.support.constraint.ConstraintLayout>

在此布局中:

  • fab 是 FloatingActionButton ,表示要展开菜单项的按钮。
  • hidden_content_container 是展开的菜单项的容器,初始时设置为 invisible
  • overlay 是一个黑色的 View,用于在展开菜单时遮盖其背后的内容。
实现动画效果

创建新的 Java 文件并添加以下代码:

public class CircularRevealHelper {

    public static void showMenu(View menuContainer, View anchorView) {
        AnimatorSet showAnimations = new AnimatorSet();

        int cx = (anchorView.getLeft() + anchorView.getRight()) / 2;
        int cy = (anchorView.getTop() + anchorView.getBottom()) / 2;

        int finalRadius = Math.max(menuContainer.getWidth(), menuContainer.getHeight());
        Animator anim = ViewAnimationUtils.createCircularReveal(menuContainer, cx, cy, 0, finalRadius);
        anim.setInterpolator(new AccelerateInterpolator());
        anim.setDuration(300);

        ObjectAnimator overlayAnimator = ObjectAnimator.ofFloat(anchorView.getRootView().findViewById(R.id.overlay), View.ALPHA, 0, 0.5f);
        overlayAnimator.setDuration(300);
        overlayAnimator.setStartDelay(300);

        menuContainer.setVisibility(View.VISIBLE);

        showAnimations.playTogether(anim, overlayAnimator);
        showAnimations.start();
    }

    public static void hideMenu(View menuContainer, View anchorView) {
        AnimatorSet hideAnimations = new AnimatorSet();

        int cx = (anchorView.getLeft() + anchorView.getRight()) / 2;
        int cy = (anchorView.getTop() + anchorView.getBottom()) / 2;

        int initialRadius = menuContainer.getWidth() / 2;
        Animator anim = ViewAnimationUtils.createCircularReveal(menuContainer, cx, cy, initialRadius, 0);
        anim.setInterpolator(new AccelerateInterpolator());
        anim.setDuration(300);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                menuContainer.setVisibility(View.INVISIBLE);
            }
        });

        ObjectAnimator overlayAnimator = ObjectAnimator.ofFloat(anchorView.getRootView().findViewById(R.id.overlay), View.ALPHA, 0.5f, 0);
        overlayAnimator.setDuration(300);

        hideAnimations.playTogether(anim, overlayAnimator);
        hideAnimations.start();
    }
}

这个类提供两个静态方法:

  • showMenu() 在给定的 anchorView 处展开菜单。
  • hideMenu() 关闭菜单并将其折叠回 anchorView 处。
将逻辑添加到 Activity 或 Fragment 中

创建一个新的 ViewModel 文件并添加以下代码:

public class MainViewModel extends ViewModel {

    private MutableLiveData<Boolean> showMenu = new MutableLiveData<>();
    private MutableLiveData<View.OnClickListener> fabClickListener = new MutableLiveData<>();

    public MainViewModel() {
        showMenu.setValue(false);
        fabClickListener.setValue(v -> showMenu());
    }

    public LiveData<Boolean> getShowMenu() {
        return showMenu;
    }

    public LiveData<View.OnClickListener> getFabClickListener() {
        return fabClickListener;
    }

    public void showMenu() {
        showMenu.setValue(true);
    }

    public void hideMenu() {
        showMenu.setValue(false);
    }
}

这里创建了一个 MainViewModel 类,其中包含两个 LiveData: showMenufabClickListener。这个类的构造函数将 showMenu 的初始值设置为 false

接下来,在您的 Activity 或 Fragment 中初始化该 ViewModel:

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;

    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        binding.setViewModel(viewModel);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(v -> viewModel.getFabClickListener().getValue().onClick(v));
    }
}

在这里,使用 DataBindingUtil 来设置 Activity 的布局,并获取 MainViewModel 实例。接下来,您将视图绑定到该 ViewModel,并将 ViewModel 中的 fabClickListener 属性添加到实际的悬浮按钮上。

最后,在您的 Activity 或 Fragment 中,将 showMenu 属性观察到,并根据其值展开或折叠菜单:

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;

    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        binding.setViewModel(viewModel);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(v -> viewModel.getFabClickListener().getValue().onClick(v));

        viewModel.getShowMenu().observe(this, show -> {
            View menuContainer = findViewById(R.id.hidden_content_container);
            if (show) {
                CircularRevealHelper.showMenu(menuContainer, fab);
            } else {
                CircularRevealHelper.hideMenu(menuContainer, fab);
            }
        });
    }
}

在这里,您可以使用 CircularRevealHelper 类来实现展开和折叠菜单的动画。此代码块将观察到 showMenu 属性的更改,并相应地调用 showMenu()hideMenu() 方法。

结论

使用本示例,您可以将一个菜单展开到 CircularRevealFrameLayout 中。此示例演示了如何使用 FloatingActionButton、CircularReveal 动画和 ConstraintLayout 来实现该效果。