50

ボタンやその他のビューに「リップル効果 - タッチ フィードバック」を実装する方法を理解しようとしています。SO でのリップル タッチ効果に関連する質問を見て、いくつかの洞察を得ました。この Java コードを使用して波及効果を得ることができました。

import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RadialGradient;
import android.graphics.Region;
import android.graphics.Shader;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.AccelerateInterpolator;
import android.widget.Button;

public class MyButton extends Button {

    private float mDownX;
    private float mDownY;

    private float mRadius;

    private Paint mPaint;

    public MyButton(final Context context) {
        super(context);
        init();
    }

    public MyButton(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyButton(final Context context, final AttributeSet attrs,
            final int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAlpha(100);
    }

    @Override
    public boolean onTouchEvent(@NonNull final MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
            mDownX = event.getX();
            mDownY = event.getY();

            ObjectAnimator animator = ObjectAnimator.ofFloat(this, "radius", 0,
                    getWidth() * 3.0f);
            animator.setInterpolator(new AccelerateInterpolator());
            animator.setDuration(400);
            animator.start();
        }
        return super.onTouchEvent(event);
    }

    public void setRadius(final float radius) {
        mRadius = radius;
        if (mRadius > 0) {
            RadialGradient radialGradient = new RadialGradient(mDownX, mDownY,
                    mRadius * 3, Color.TRANSPARENT, Color.BLACK,
                    Shader.TileMode.MIRROR);
            mPaint.setShader(radialGradient);
        }
        invalidate();
    }

    private Path mPath = new Path();
    private Path mPath2 = new Path();

    @Override
    protected void onDraw(@NonNull final Canvas canvas) {
        super.onDraw(canvas);

        mPath2.reset();
        mPath2.addCircle(mDownX, mDownY, mRadius, Path.Direction.CW);

        canvas.clipPath(mPath2);

        mPath.reset();
        mPath.addCircle(mDownX, mDownY, mRadius / 3, Path.Direction.CW);

        canvas.clipPath(mPath, Region.Op.DIFFERENCE);

        canvas.drawCircle(mDownX, mDownY, mRadius, mPaint);
    }
}

しかし、私はXMLアプローチを使いたいです。どうすればこれを達成できますか? 私はこれこれを見てきましたが、私はまだスタイルに慣れていないので、波及効果を達成するのは難しいと感じています.

次の XML コードを含むボタンがあります。

 <Button
            android:id="@+id/button_email"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="0.50"
            android:gravity="center"
            android:text="@string/email" />

このボタンの波及効果を得るにはどうすればよいですか。誰かが私を導くことができれば、私は感謝します。

[編集] 上記のリンクの 1 つに記載されているように、ripple.xml と background.xml を追加します。res に drawable-v21 フォルダーを作成し、そこに以下のファイルを追加しました。

リップル.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@android:color/black" >
    <item android:drawable="@drawable/background">
    </item>
</ripple>

background.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="@android:color/darker_gray" />
</shape>

ボタンの背景として波紋を追加しました。これがボタンのxmlです。

<Button
    android:id="@+id/button_email"
    android:layout_width="0dip"
    android:layout_height="wrap_content"
    android:layout_weight="0.50"
    android:gravity="center"
    android:background="@drawable/ripple"
    android:text="@string/email" />

アプリケーションを実行すると、ResourceNotFoundException が発生します。これがlogcatトレースです..

07-21 17:03:39.043: E/AndroidRuntime(15710): FATAL EXCEPTION: main
07-21 17:03:39.043: E/AndroidRuntime(15710): Process: com.xx.xxx, PID: 15710
07-21 17:03:39.043: E/AndroidRuntime(15710): android.view.InflateException: Binary XML file line #60: Error inflating class <unknown>
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.createView(LayoutInflater.java:620)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:669)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:694)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:758)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.xx.xxx.BusinessAdapter.onCreateViewHolder(BusinessAdapter.java:106)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.xx.xxx.BusinessAdapter.onCreateViewHolder(BusinessAdapter.java:1)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:2915)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:2511)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.LinearLayoutManager$RenderState.next(LinearLayoutManager.java:1425)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:999)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:524)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1461)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:1600)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:374)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1983)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1740)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:996)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5600)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer.doCallbacks(Choreographer.java:574)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer.doFrame(Choreographer.java:544)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.os.Handler.handleCallback(Handler.java:733)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.os.Handler.dispatchMessage(Handler.java:95)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.os.Looper.loop(Looper.java:136)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.app.ActivityThread.main(ActivityThread.java:5001)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Method.invokeNative(Native Method)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Method.invoke(Method.java:515)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at dalvik.system.NativeStart.main(Native Method)
07-21 17:03:39.043: E/AndroidRuntime(15710): Caused by: java.lang.reflect.InvocationTargetException
07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Constructor.constructNative(Native Method)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.createView(LayoutInflater.java:594)
07-21 17:03:39.043: E/AndroidRuntime(15710):    ... 50 more
07-21 17:03:39.043: E/AndroidRuntime(15710): Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x1/d=0x7f020075 a=-1 r=0x
4

7 に答える 7

72

材料コンポーネントの更新:

マテリアル コンポーネント ライブラリを使用すると、リップルを簡単に適用できます。と属性を
使用するだけです。MaterialButtonapp:rippleColor

<com.google.android.material.button.MaterialButton
    app:rippleColor="@color/my_selector"
    ../>

次のようなセレクターを使用します。

<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:alpha="..." android:color="?attr/colorOnPrimary" android:state_pressed="true"/>
  <item android:alpha="..." android:color="?attr/colorOnPrimary" android:state_focused="true" android:state_hovered="true"/>
  <item android:alpha="..." android:color="?attr/colorOnPrimary" android:state_focused="true"/>
  <item android:alpha="..." android:color="?attr/colorOnPrimary" android:state_hovered="true"/>
  <item android:alpha="..." android:color="?attr/colorOnPrimary"/>

</selector>

古い答え
次のようなことができます:

<Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@drawable/ripple"
      
    />

ripple.xml は次の場所にあります。

<ripple xmlns:android="http://schemas.android.com/apk/res/android" 
                      android:color="?android:colorControlHighlight">
        <item android:id="@android:id/mask">
            <shape android:shape="oval">
                <solid android:color="?android:colorAccent" />
            </shape>
        </item>
 </ripple>
于 2014-07-21T13:51:33.133 に答える
30

?attr/selectableItemBackground以下のように、API 21+ のボタンの背景を配置するだけです。

<Button
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:background="?attr/selectableItemBackground"
        android:text="Button" />
于 2015-09-28T03:10:40.463 に答える
20

lollipop(API>21) の場合、ドローアブルで btn_ripple_effect.xml としてファイルを作成し、コードの下に配置します

<?xml version="1.0" encoding="utf-8"?>

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:color="?android:colorAccent"
    tools:targetApi="lollipop">
    <item android:drawable="@color/cancel_btn_clr" /> <!-- default -->
    <item android:id="@android:id/mask">
        <shape android:shape="rectangle">
            <solid android:color="?android:colorAccent" />
        </shape>
    </item>
</ripple>

ロリポップ前 (API<21) の場合、drawable-v21 フォルダーに btn_ripple_effect.xml としてファイルを作成し、コードの下に配置します。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true">
        <shape>
            <solid android:color="@color/colorAccent"></solid>
        </shape>
    </item>

    <item>
        <shape>
            <solid android:color="@color/cancel_btn_clr"></solid>
        </shape>
    </item>

</selector>
于 2016-07-15T10:53:47.897 に答える
12

上記の回答に少し追加:マスクの色は決して使用されないことに注意してください。

リップルを使用すると、より複雑なことも実行できます。たとえば、リップル ボタンに境界線が必要な場合は、レイヤー リストのように使用できます。

<ripple
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:color="?android:colorControlHighlight">

    <!-- Note: <ripple> acts like a layer-list -->
    <item android:id="@android:id/mask">
        <shape android:shape="oval">
            <!-- This color is not displayed in any way -->
            <solid android:color="@android:color/black" />
        </shape>
    </item>

    <!-- This is the border -->
    <item>
        <shape android:shape="rectangle">
            <corners android:radius="3dp"/>
            <!-- Use your border color in place of #f00 -->
            <stroke android:width="1dp" android:color="#f00"/>
        </shape>
    </item>
 </ripple>

id を持つ要素@android:id/maskは、波及効果が停止する場所を示すためにのみ使用されることに注意してください。ボタン全体をカバーしたい場合は、 を に変更できandroid:shapeますrectangle。これでさらに多くの興味深いことが想像できます!

また、21 歳未満のデバイス用のバックアップ ドローアブルがあることを確認してください。そうしないと、古いデバイスでアプリがクラッシュします。

于 2015-03-12T20:11:12.997 に答える
7

これをandroid:foregroundで使用する最良の方法は、独自の背景も使用できるためです。

android:foreground="?android:attr/selectableItemBackground"

例:

<android.support.v7.widget.AppCompatButton
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:foreground="?android:attr/selectableItemBackground"
    android:background="@color/button.normal"
    android:textColor="@color/white"/>
于 2017-01-05T05:34:22.927 に答える
3

波及効果は、アプリケーションのいくつかのボタンに適用したかったものであり、投稿で発生したため、調査していました。あなたの質問は、XMLを使用して波及効果を追加する方法に関する回答を探していますが、その属性を追加しようとすると、v21が必要であることがわかります.

v21 より下位をターゲットにしている場合、Button (または ImageButton など) を拡張する新しいクラスは、コンパイラからの苦情を回避します。

上記のカスタム クラスを実装する方法についての説明がなかったので、私が記入しようと思いました。必要なことは、新しいクラスを作成し、XML で「Button」を「the.package.name.MyButton」に変更することだけです。

から:

 <Button
    android:id="@+id/Button"     

    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

に:

 <the.package.name.MyButton
   android:id="@+id/Button"     

    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

それでおしまい。これで、ボタンを押すと、その境界内に波紋が含まれます。

私はこのアプローチが好きで、波紋が限界を超えて広がることを願っています。小さなボタンの場合、この波及効果により、ボタンが実際にどれだけ正方形または長方形であるかが強調されます。波紋が完全な半径に達するまで続けた方が、視覚的にはより満足のいくものになります。

于 2015-11-06T17:31:34.270 に答える
1

clickableビューにastrueおよびas属性を追加できbackgroundます。foreround?attr/selectableItemBackground

<Button
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="Button"
     android:clickable="true"
     android:background="?attr/selectableItemBackground"
     android:textColor="@android:color/white"/>

ビューがすでにbackground何かで満たされている場合はforegroundselectableItemBackground

<Button
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="Button"
     android:clickable="true"
     android:foreground="?attr/selectableItemBackground"
     android:background="@color/colorPrimary"
     android:textColor="@android:color/white"/>
于 2017-06-22T09:59:11.393 に答える