সমর্থন লাইব্রেরি ব্যবহার করে রিপাল অ্যানিমেশন কীভাবে অর্জন করবেন?


171

আমি বোতাম ক্লিকে একটি রিপল অ্যানিমেশন যুক্ত করার চেষ্টা করছি। আমি নীচে পছন্দ করি তবে এটির 21 মিনিটে minSdKVersion প্রয়োজন।

ripple.xml

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="?android:colorAccent" />
        </shape>
    </item>
</ripple>

বোতাম

<com.devspark.robototextview.widget.RobotoButton
    android:id="@+id/loginButton"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/ripple"
    android:text="@string/login_button" />

আমি এটিকে নকশাগুলির লাইব্রেরির সাথে সামঞ্জস্যপূর্ণ করতে চাই।

এটি কিভাবে করা যায়?

উত্তর:


380

বেসিক রিপল সেটআপ

  • লীপগুলি ভিউয়ের মধ্যে রয়েছে।
    android:background="?selectableItemBackground"

  • রিপলগুলি যা দেখার সীমা ছাড়িয়ে যায়:
    android:background="?selectableItemBackgroundBorderless"

    জাভা কোডে এক্সএমএল রেফারেন্স সমাধান করার জন্য এখানে একবার দেখুন ?(attr)

সমর্থন লাইব্রেরি

  • ব্যবহার ?attr:(বা ?এর সাধারণভাবে সংক্ষেপে) পরিবর্তে ?android:attrরেফারেন্স সমর্থন গ্রন্থাগার , তাই এপিআই 7 প্রাপ্তিসাধ্য ফিরে।

চিত্র / ব্যাকগ্রাউন্ড সহ লহরগুলি

  • একটি ইমেজ বা পটভূমি থাকতে হবে এবং সহজ সমাধান লহরী ওভারলেয়িং মোড়ানো হয় Viewএকটি FrameLayoutসঙ্গে লহরী সেট দিয়ে setForeground()বা setBackground()

সত্যিই অন্যথায় এটি করার কোনও পরিষ্কার উপায় নেই।


38
এটি 21 এর আগের সংস্করণগুলিতে
রিপল

21
এটি রিপল সমর্থন যোগ করতে পারে না তবে এই সমাধানটি সুন্দরভাবে হ্রাস পায়। এটি আসলে আমার যে বিশেষ সমস্যাটি ছিল তা সমাধান করেছে। আমি এল এর উপর একটি রিপল ইফেক্ট চেয়েছিলাম এবং অ্যান্ড্রয়েডের পূর্ববর্তী সংস্করণে একটি সহজ নির্বাচন করতে চাই।
ডেভ জেনসেন

4
@ অ্যান্ড্রয়েড ডেভ, @ ডেভ জেনসেন: আসলে, ভি 7 সমর্থন লাইব্রেরির ?attr:পরিবর্তে ?android:attrরেফারেন্স ব্যবহার করে, আপনি এটি ব্যবহার করে ধরে নিলেন, আপনাকে পিপিআই 7 এর সাথে সামঞ্জস্যতা দেয় See দেখুন: বিকাশকারী.অ্যান্ড্রয়েড /
ভি 7

14
আমিও যদি পটভূমির রঙ পেতে চাই?
স্ট্যানলে সান্টোসো

9
রিপল এফেক্টটি << 21 এর জন্য নয় The রিপলটি উপাদান ডিজাইনের একটি ক্লিক প্রভাব। গুগল ডিজাইন টিমের দৃষ্টিভঙ্গি এটি প্রাক-ললিপপ ডিভাইসে প্রদর্শিত হয় না। প্রাক-ললিপপের নিজস্ব ক্লিক এফেক্ট রয়েছে (হালকা-নীল কভারের ডিফল্ট)। প্রদত্ত উত্তরটি সিস্টেমের ডিফল্ট ক্লিক-প্রভাবটি ব্যবহার করার পরামর্শ দেয়। আপনি যদি ক্লিক এফেক্টের রঙগুলি কাস্টমাইজ করতে চান তবে আপনাকে একটি অঙ্কনীয় তৈরি করতে হবে এবং এটি রিপল ক্লিক-ইফেক্টের জন্য রেস / ড্রইয়েবল-ভি 21 এ স্থাপন করতে হবে (<রিপ্লে> ড্রইবলের সাহায্যে), এবং রেস / ড্রয়যোগ্য অ-এর জন্য রিপল ক্লিক এফেক্ট (<সিলেক্টর> সাধারণত অঙ্কনযোগ্য)
এনবিটিকি

55

আমি পূর্বে এই প্রশ্নটিকে অফ-টপিক হিসাবে বন্ধ করার পক্ষে ভোট দিয়েছিলাম তবে আসলে আমি আমার মন পরিবর্তন করেছি কারণ এটি বেশ দুর্দান্ত ভিজ্যুয়াল এফেক্ট যা দুর্ভাগ্যক্রমে এখনও সমর্থন লাইব্রেরির অংশ নয়। এটি সম্ভবত ভবিষ্যতের আপডেটে প্রদর্শিত হবে, তবে কোনও সময়সীমা ঘোষিত হয়নি।

ভাগ্যক্রমে কয়েকটি কাস্টম বাস্তবায়ন ইতিমধ্যে উপলব্ধ:

মেটেরিয়াল থিমযুক্ত উইজেট সেট সহ অ্যান্ড্রয়েডের পুরানো সংস্করণগুলির সাথে সামঞ্জস্যপূর্ণ:

সুতরাং আপনি এইগুলির মধ্যে একটি বা অন্য "ম্যাটারিয়াল উইজেট" বা আরও কিছু জন্য গুগল চেষ্টা করতে পারেন ...


12
এটি এখন সমর্থন লাইব্রেরির অংশ, আমার উত্তর দেখুন।
বেন দে লা হেই

ধন্যবাদ! আমি দ্বিতীয় লাইব ব্যবহার করেছি , প্রথমটি ধীর ফোনে খুব ধীর ছিল।
ফেরান মেলিনচ

27

আমি একটি সাধারণ ক্লাস তৈরি করেছিলাম যা রিপল বোতামগুলি তৈরি করে, শেষ পর্যন্ত আমার কখনই এটির প্রয়োজন ছিল না এটি সর্বোত্তম নয়, তবে এটি এখানে:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;

public class RippleView extends Button
{
    private float duration = 250;

    private float speed = 1;
    private float radius = 0;
    private Paint paint = new Paint();
    private float endRadius = 0;
    private float rippleX = 0;
    private float rippleY = 0;
    private int width = 0;
    private int height = 0;
    private OnClickListener clickListener = null;
    private Handler handler;
    private int touchAction;
    private RippleView thisRippleView = this;

    public RippleView(Context context)
    {
        this(context, null, 0);
    }

    public RippleView(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public RippleView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init()
    {
        if (isInEditMode())
            return;

        handler = new Handler();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.WHITE);
        paint.setAntiAlias(true);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

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

        if(radius > 0 && radius < endRadius)
        {
            canvas.drawCircle(rippleX, rippleY, radius, paint);
            if(touchAction == MotionEvent.ACTION_UP)
                invalidate();
        }
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event)
    {
        rippleX = event.getX();
        rippleY = event.getY();

        switch(event.getAction())
        {
            case MotionEvent.ACTION_UP:
            {
                getParent().requestDisallowInterceptTouchEvent(false);
                touchAction = MotionEvent.ACTION_UP;

                radius = 1;
                endRadius = Math.max(Math.max(Math.max(width - rippleX, rippleX), rippleY), height - rippleY);
                speed = endRadius / duration * 10;
                handler.postDelayed(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        if(radius < endRadius)
                        {
                            radius += speed;
                            paint.setAlpha(90 - (int) (radius / endRadius * 90));
                            handler.postDelayed(this, 1);
                        }
                        else
                        {
                            clickListener.onClick(thisRippleView);
                        }
                    }
                }, 10);
                invalidate();
                break;
            }
            case MotionEvent.ACTION_CANCEL:
            {
                getParent().requestDisallowInterceptTouchEvent(false);
                touchAction = MotionEvent.ACTION_CANCEL;
                radius = 0;
                invalidate();
                break;
            }
            case MotionEvent.ACTION_DOWN:
            {
                getParent().requestDisallowInterceptTouchEvent(true);
                touchAction = MotionEvent.ACTION_UP;
                endRadius = Math.max(Math.max(Math.max(width - rippleX, rippleX), rippleY), height - rippleY);
                paint.setAlpha(90);
                radius = endRadius/4;
                invalidate();
                return true;
            }
            case MotionEvent.ACTION_MOVE:
            {
                if(rippleX < 0 || rippleX > width || rippleY < 0 || rippleY > height)
                {
                    getParent().requestDisallowInterceptTouchEvent(false);
                    touchAction = MotionEvent.ACTION_CANCEL;
                    radius = 0;
                    invalidate();
                    break;
                }
                else
                {
                    touchAction = MotionEvent.ACTION_MOVE;
                    invalidate();
                    return true;
                }
            }
        }

        return false;
    }

    @Override
    public void setOnClickListener(OnClickListener l)
    {
        clickListener = l;
    }
}

সম্পাদনা

যেহেতু অনেক লোক এই জাতীয় কিছু খুঁজছেন আমি এমন একটি শ্রেণি তৈরি করেছি যা অন্যান্য মতামতগুলি রিপল প্রভাবিত করতে পারে:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

public class RippleViewCreator extends FrameLayout
{
    private float duration = 150;
    private int frameRate = 15;

    private float speed = 1;
    private float radius = 0;
    private Paint paint = new Paint();
    private float endRadius = 0;
    private float rippleX = 0;
    private float rippleY = 0;
    private int width = 0;
    private int height = 0;
    private Handler handler = new Handler();
    private int touchAction;

    public RippleViewCreator(Context context)
    {
        this(context, null, 0);
    }

    public RippleViewCreator(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public RippleViewCreator(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init()
    {
        if (isInEditMode())
            return;

        paint.setStyle(Paint.Style.FILL);
        paint.setColor(getResources().getColor(R.color.control_highlight_color));
        paint.setAntiAlias(true);

        setWillNotDraw(true);
        setDrawingCacheEnabled(true);
        setClickable(true);
    }

    public static void addRippleToView(View v)
    {
        ViewGroup parent = (ViewGroup)v.getParent();
        int index = -1;
        if(parent != null)
        {
            index = parent.indexOfChild(v);
            parent.removeView(v);
        }
        RippleViewCreator rippleViewCreator = new RippleViewCreator(v.getContext());
        rippleViewCreator.setLayoutParams(v.getLayoutParams());
        if(index == -1)
            parent.addView(rippleViewCreator, index);
        else
            parent.addView(rippleViewCreator);
        rippleViewCreator.addView(v);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

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

        if(radius > 0 && radius < endRadius)
        {
            canvas.drawCircle(rippleX, rippleY, radius, paint);
            if(touchAction == MotionEvent.ACTION_UP)
                invalidate();
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event)
    {
        return true;
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event)
    {
        rippleX = event.getX();
        rippleY = event.getY();

        touchAction = event.getAction();
        switch(event.getAction())
        {
            case MotionEvent.ACTION_UP:
            {
                getParent().requestDisallowInterceptTouchEvent(false);

                radius = 1;
                endRadius = Math.max(Math.max(Math.max(width - rippleX, rippleX), rippleY), height - rippleY);
                speed = endRadius / duration * frameRate;
                handler.postDelayed(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        if(radius < endRadius)
                        {
                            radius += speed;
                            paint.setAlpha(90 - (int) (radius / endRadius * 90));
                            handler.postDelayed(this, frameRate);
                        }
                        else if(getChildAt(0) != null)
                        {
                            getChildAt(0).performClick();
                        }
                    }
                }, frameRate);
                break;
            }
            case MotionEvent.ACTION_CANCEL:
            {
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }
            case MotionEvent.ACTION_DOWN:
            {
                getParent().requestDisallowInterceptTouchEvent(true);
                endRadius = Math.max(Math.max(Math.max(width - rippleX, rippleX), rippleY), height - rippleY);
                paint.setAlpha(90);
                radius = endRadius/3;
                invalidate();
                return true;
            }
            case MotionEvent.ACTION_MOVE:
            {
                if(rippleX < 0 || rippleX > width || rippleY < 0 || rippleY > height)
                {
                    getParent().requestDisallowInterceptTouchEvent(false);
                    touchAction = MotionEvent.ACTION_CANCEL;
                    break;
                }
                else
                {
                    invalidate();
                    return true;
                }
            }
        }
        invalidate();
        return false;
    }

    @Override
    public final void addView(@NonNull View child, int index, ViewGroup.LayoutParams params)
    {
        //limit one view
        if (getChildCount() > 0)
        {
            throw new IllegalStateException(this.getClass().toString()+" can only have one child.");
        }
        super.addView(child, index, params);
    }
}

অন্যথায় যদি (ক্লিকলিস্টার! = নাল) L ক্লিক করুনলাইস্টনার.অন ক্লিক করুন (এটির রিপলভিউ); }
ভোলডিমির কুলিক

বাস্তবায়নের জন্য সহজ ... প্লাগ ও প্লে :)
রণজিৎ কুমার

আমি যদি পুনর্ব্যবহারযোগ্য ভিউয়ের প্রতিটি দৃশ্যের উপরে এই শ্রেণিটি ব্যবহার করি তবে আমি ক্লাসকাস্টএক্সেপশন পাচ্ছি।
আলী_ওয়ারিস

1
@ অলি_ওয়ারিস সমর্থন লাইব্রেরি এই দিনগুলিতে লহরগুলি মোকাবেলা করতে পারে তবে রিপল addRippleToViewইফেক্ট যুক্ত করার পরিবর্তে আপনাকে যা করতে হবে তা হ'ল এটি করা fix বরং প্রতিটি দৃশ্য করতে RecyclerViewএকটিRippleViewCreator
নিকোলাস টিলার

17

কখনও কখনও আপনার একটি কাস্টম ব্যাকগ্রাউন্ড থাকে, সেই ক্ষেত্রে আরও ভাল সমাধান ব্যবহার করা হয় android:foreground="?selectableItemBackground"


2
হ্যাঁ, তবে এটি API> = 23 বা 21 এপিআই সহ ডিভাইসগুলিতে কাজ করে তবে কেবল কার্ডভিউ বা
ফ্রেমলাইউটে

17

এটা খুবই সাধারণ ;-)

প্রথমে আপনাকে দুটি পুরানো এপিআই সংস্করণের জন্য দুটি আঁকুনযোগ্য ফাইল তৈরি করতে হবে এবং অন্যটি একটি নতুন সংস্করণে অবশ্যই তৈরি করতে হবে, অবশ্যই! আপনি যদি সর্বশেষ এপিআই সংস্করণ অ্যান্ড্রয়েড স্টুডিওর জন্য অঙ্কনযোগ্য ফাইল তৈরি করেন তবে আপনাকে স্বয়ংক্রিয়ভাবে পুরানো তৈরি করার পরামর্শ দিচ্ছে। এবং অবশেষে আপনার ব্যাকগ্রাউন্ড ভিউতে এটি আকর্ষণীয় সেট করুন।

নতুন এপিআই সংস্করণ (রেজো / অঙ্কনযোগ্য-ভি 21 / রিপল.এক্সএমএল) এর জন্য নমুনা অঙ্কনীয়:

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:colorControlHighlight">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/colorPrimary" />
            <corners android:radius="@dimen/round_corner" />
        </shape>
    </item>
</ripple>

পুরানো এপিআই সংস্করণ (পুনরায় / অঙ্কনযোগ্য / রিপল.এক্সএমএল) এর জন্য নমুনা অঙ্কনযোগ্য

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@color/colorPrimary" />
    <corners android:radius="@dimen/round_corner" />
</shape>

রিপল অঙ্কনযোগ্য সম্পর্কে আরও তথ্যের জন্য কেবল এখানে দেখুন: https://developer.android.com/references/android/ographicics/drawable/RippleDrawable.html


1
এটা সত্যিই খুব সহজ!
আদিত্য এস।

এই সমাধানটি অবশ্যই আরও অনেকগুলি আপডভোট হওয়া উচিত! ধন্যবাদ.
জেরাকবাকাকুব

0

কখনও কখনও কোনও বিন্যাস বা উপাদানগুলিতে এই লাইনটি ব্যবহারযোগ্য হবে।

 android:background="?attr/selectableItemBackground"

মত.

 <RelativeLayout
                android:id="@+id/relative_ticket_checkin"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="?attr/selectableItemBackground">
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.