如何设置cardview ripple热点?

时间:2016-10-19 14:24:14

标签: cardview

触点的涟漪

谷歌已经开始向应用程序开发人员指出他们在Material Design风格的UI中使用涟漪动画时,这些涟漪似乎不会从触发动画的触摸点散发出来。

使用谷歌的搜索引擎,我发现的唯一可以解释如何使这项工作成为Lucas Rocha的TwoWayView库问题的评论。幸运的是,这个评论足以让我创造出似乎有用的东西。

正如Butcher先生在他的推文中提示的那样,关键似乎是Drawable上的setHotspot()方法。在API Level 21中添加,这教导了drawable一个“热点”,而RippleDrawable显然使用它作为涟漪效应的发散点。 setHotspot()获取一对浮点值,大概是在OnTouchListener中使用setHotspot(),因为MotionEvent使用浮点值报告触摸事件的X / Y位置。

此示例应用程序演示了在RecyclerView的上下文中使用setHotspot(),作为我正在为下一本书更新工作的50多页的章节的一部分。此RecyclerView使用LinearLayoutManager来复制经典ListView的基本结构。我的行基于CardView:

```的xml

因此,如果用户触摸一行,我会将触摸点传播到背景作为其热点。我特意返回false表示我们没有使用触摸事件,因此如果需要,它将继续使用其他事件处理程序。

如果没有这个setHotspot()调用,RippleDrawable似乎默认为drawable的中心。因此,对于列表样式的RecyclerView的行,涟漪效应将从行的中心发出。 setHotspot(),与触摸事件相关联,改变了发射点。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:cardview="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_margin="4dp"
  cardview:cardCornerRadius="4dp">

  <LinearLayout
    android:id="@+id/row_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="?android:attr/selectableItemBackground">

    <!-- other widgets in here -->

    </LinearLayout>

  </LinearLayout>

</android.support.v7.widget.CardView>
```

The LinearLayout that the CardView wraps has ?android:attr/selectableItemBackground as its background, pulling in a theme attribute. If this app runs on API Level 21, that background will be a RippleDrawable.

When I set up the row, I attach an OnTouchListener to set the hotspot, but only on API Level 21+ devices (as setHotspot() does not exist before then):

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  row.setOnTouchListener(new View.OnTouchListener() {
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean onTouch(View v, MotionEvent event) {
      v
        .findViewById(R.id.row_content)
        .getBackground()
        .setHotspot(event.getX(), event.getY());

      return(false);
    }
  });
}

这似乎有效。我不知道这是否是正式的正确答案,因为我没有看到任何来自Google的代码如何实现这一点(例如,搜索SDK样本的setHotspot()没有任何结果)。特别是,直接在后台调用setHotspot()会让我担心(我们应该首先调用mutate()吗?)。因此,想象一粒盐,一边长约15厘米,并采用这种实施方式。

1 个答案:

答案 0 :(得分:0)

  

显示或动画时,显示动画可为用户提供视觉连续性   隐藏一组UI元素。该   ViewAnimationUtils.createCircularReveal()方法使您能够   动画剪裁圆圈以显示或隐藏视图。

     

使用此效果显示以前不可见的视图:

View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = myView.getWidth() / 2;
int cy = myView.getHeight() / 2;

// get the final radius for the clipping circle
float finalRadius = (float) Math.hypot(cx, cy);

// create the animator for this view (the start radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);

// make the view visible and start the animation
myView.setVisibility(View.VISIBLE);
anim.start();
  

使用此效果隐藏以前可见的视图:

// previously visible view
final View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = myView.getWidth() / 2;
int cy = myView.getHeight() / 2;

// get the initial radius for the clipping circle
float initialRadius = (float) Math.hypot(cx, cy);

// create the animation (the final radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);

// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        myView.setVisibility(View.INVISIBLE);
    }
});

// start the animation
anim.start();