图像顶部的波纹效果 - Android [英] Ripple effect on top of Image - Android

查看:20
本文介绍了图像顶部的波纹效果 - Android的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在我最新的副项目中试验涟漪动画.我在寻找在某些情况下用于触摸事件的优雅"解决方案时遇到了一些麻烦.即使用图像,尤其是在列表、网格和回收视图中.动画似乎总是在视图后面进行动画处理,而不是在视图之上.这在 Buttons 和 TextViews 中不是问题,但如果您有图像的 GridView,波纹会出现在实际图像的后面或下方.显然这不是我想要的,虽然我认为有一些解决方案可以解决,但我希望有一些我不知道的更简单的东西.

I've been experimenting with the ripple animation in my latest side project. I'm having some trouble finding an "elegant" solution to using it in certain situations for touch events. Namely with images, especially in list, grid, and recycle views. The animation almost always seems to animate behind the view, not the on top of it. This is a none issue in Buttons and TextViews but if you have a GridView of images, the ripple appears behind or below the actual image. Obviously this is not what I want, and while there are solutions that I consider to be a work around, I'm hoping there is something simpler i'm just unaware of.

我使用以下代码来实现带有图像的自定义网格视图.我会提供完整的代码点击这里,所以你可以按照你的选择进行操作.

I use the following code to achieve a custom grid view with images. I'll give full code CLICK HERE so you can follow along if you choose.

现在只是重要的事情.为了让我的图像在触摸时动画,我需要这个

Now just the important stuff. In order to get my image to animate on touch I need this

button_ripple.xml

<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/cream_background">
    <item>
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
            <!-- Pressed -->
            <item
                android:drawable="@color/button_selected"
                android:state_pressed="true"/>
            <!-- Selected -->
            <item
                android:drawable="@color/button_selected"
                android:state_selected="true"/>
            <!-- Focus -->
            <item
                android:drawable="@color/button_selected"
                android:state_focused="true"/>
            <!-- Default -->
            <item android:drawable="@color/transparent"/>
        </selector>
    </item>
</ripple>

custom_grid.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:gravity="center_horizontal"
              android:orientation="horizontal">

    <ImageView
        android:id="@+id/sceneGridItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/button_ripple"
        android:gravity="center_horizontal"/>

</LinearLayout>

activity_main.xml

<GridView
    android:id="@+id/sceneGrid"
    android:layout_marginTop="15dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:verticalSpacing="15dp"
    android:numColumns="5" />

发生所有魔法和问题的那一行是我设置背景的时候.虽然这实际上在我的图像视图上给了我一个涟漪动画,但它在图像视图的后面设置了动画.我希望动画出现在图像的顶部.所以我尝试了一些不同的东西,比如

The line where all magic and problems occur is when I set the background. While this does in fact give me a ripple animation on my imageview, it animates behind the imageview. I want the animation to appear on top of the image. So I tried a few different things like

将整个网格背景设置为 button_ripple.

<GridView
    android:id="@+id/sceneGrid"
    android:layout_marginTop="15dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:verticalSpacing="15dp"
    android:background="@drawable/button_ripple"
    android:numColumns="5" />

它完全符合你的想法,现在整个网格都有一个半透明的背景,无论我按下什么图像,整个网格都会从网格的中心开始动画.虽然这有点酷,但这不是我想要的.

It does exactly what you'd think, now the entire grid has a semi transparent background and no matter what image i press the entire grid animates from the center of the grid. While this is kind of cool, its not what I want.

将根/父背景设置为 button_ripple.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:gravity="center_horizontal"
                  android:background="@drawable/button_ripple"
                  android:orientation="horizontal">

该区域现在更大并填充了网格的整个单元格(不仅仅是图像),但它并没有将其带到前面.

The area is now larger and fills the entire cell of the grid (not just the image), however it doesn't bring it to the front.

将custom_grid.xml 更改为RelativeLayout 并将两个ImageView 置于彼此之上

custom_grid.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:orientation="horizontal">

    <ImageView
        android:id="@+id/gridItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true" />

    <ImageView
        android:id="@+id/gridItemOverlay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:background="@drawable/button_ripple" />

</RelativeLayout>

CustomGridAdapter.java

....
gridItemOverLay = (ImageView) findViewById(R.id.gridItemOverlay);
gridItemOverlay.bringToFront();

这有效.现在底部 ImageView 包含我的图像,顶部动画,给人一种波纹动画的错觉在我的图像顶部.老实说,尽管这是一种解决方法.我觉得这不是它的本意.所以我问你们好人,有没有更好的方法,甚至是不同的方法?

This works. Now the bottom ImageView contains my image, and the top animates, giving the illusion of a ripple animation on top of my image. Honestly though this is a work around. I feel like this is not how it was intended. So I ask you fine people, is there a better way or even a different way?

推荐答案

我喜欢 android 开发人员的回答,所以我决定研究如何在代码中完成他的解决方案的第 2 步.

I liked android developer's answer so I decided to investigate how to do step 2 of his solution in code.

您需要从 Jake Wharton 获取这段代码:https://gist.github.com/JakeWharton/0a251d67649305d84e8a

You need to get this piece of code from Jake Wharton here : https://gist.github.com/JakeWharton/0a251d67649305d84e8a

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;


public class ForegroundImageView extends ImageView {
  private Drawable foreground;


  public ForegroundImageView(Context context) {
    this(context, null);
  } 


  public ForegroundImageView(Context context, AttributeSet attrs) {
    super(context, attrs);


    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundImageView);
    Drawable foreground = a.getDrawable(R.styleable.ForegroundImageView_android_foreground);
    if (foreground != null) {
      setForeground(foreground);
    } 
    a.recycle();
  } 


  /** 
   * Supply a drawable resource that is to be rendered on top of all of the child 
   * views in the frame layout. 
   * 
   * @param drawableResId The drawable resource to be drawn on top of the children. 
   */ 
  public void setForegroundResource(int drawableResId) {
    setForeground(getContext().getResources().getDrawable(drawableResId));
  } 


  /** 
   * Supply a Drawable that is to be rendered on top of all of the child 
   * views in the frame layout. 
   * 
   * @param drawable The Drawable to be drawn on top of the children. 
   */ 
  public void setForeground(Drawable drawable) {
    if (foreground == drawable) {
      return; 
    } 
    if (foreground != null) {
      foreground.setCallback(null);
      unscheduleDrawable(foreground);
    } 


    foreground = drawable;


    if (drawable != null) {
      drawable.setCallback(this);
      if (drawable.isStateful()) {
        drawable.setState(getDrawableState());
      } 
    } 
    requestLayout();
    invalidate();
  } 


  @Override protected boolean verifyDrawable(Drawable who) {
    return super.verifyDrawable(who) || who == foreground;
  } 


  @Override public void jumpDrawablesToCurrentState() { 
    super.jumpDrawablesToCurrentState(); 
    if (foreground != null) foreground.jumpToCurrentState();
  } 


  @Override protected void drawableStateChanged() { 
    super.drawableStateChanged(); 
    if (foreground != null && foreground.isStateful()) {
      foreground.setState(getDrawableState());
    } 
  } 


  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    if (foreground != null) {
      foreground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
      invalidate();
    } 
  } 


  @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    if (foreground != null) {
      foreground.setBounds(0, 0, w, h);
      invalidate();
    } 
  } 


  @Override public void draw(Canvas canvas) {
    super.draw(canvas);


    if (foreground != null) {
      foreground.draw(canvas);
    } 
  } 
} 

这是 attrs.xml:

This is the attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="ForegroundImageView">
    <attr name="android:foreground"/>
  </declare-styleable>
</resources>

现在,像这样在 layout.xml 中创建 ForegroundImageView:

Now, create your ForegroundImageView like so in your layout.xml:

<com.example.ripples.ForegroundImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scaleType="centerCrop"
    android:foreground="?android:selectableItemBackground"
    android:src="@drawable/apples"
    android:id="@+id/image" />

图像现在会出现波纹.

这篇关于图像顶部的波纹效果 - Android的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆