Как добавить анимацию свечения на кнопку?

Как создать подобную анимацию на кнопке?

введите сюда описание изображения

С помощью com.facebook.shimmer:shimmer происходит затемнение. Другие похожие библиотеки вообще целиком цветом заливают для показа "скелета" во время загрузки.

введите сюда описание изображения

<com.facebook.shimmer.ShimmerFrameLayout
    app:shimmer_auto_start="true"
    app:shimmer_duration="2000"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:background="@drawable/gradient"
        android:text="@string/btn"
        android:textColor="@android:color/white"
        app:backgroundTint="@null" />

</com.facebook.shimmer.ShimmerFrameLayout>

Ответы (1 шт):

Автор решения: Style-7

Мой вариант через анимацию custom drawable. Заводим переменную:

private DrawableGlare drawable_glare = new DrawableGlare();

Установка на кнопку в методе активности onCreate (или аналог во фрагменте)

button.setBackground( drawable_glare );.

Запуск анимации в методе onResume одноименным методом и остановка в onPause аналогично. Цвет и размер текста кнопки задается в xml разметке.

public class DrawableGlare extends Drawable{
    final private int color0 = 0xff0080ff;
    final private int color1 = 0xffff00ff;
    final private int anim_duration = 2000;

    private Point size = new Point(0,0);
    private LinearGradient lg;
    private Path path = new Path();
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Bitmap bm_glare;
    private int pos_x;
    private ValueAnimator animator = ValueAnimator.ofFloat(0,1);
    {
        animator.setDuration( anim_duration );
        animator.setInterpolator( new LinearInterpolator() );
        animator.setRepeatMode( ValueAnimator.RESTART );
        animator.setRepeatCount( ValueAnimator.INFINITE );
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
            @Override
            public void onAnimationUpdate(ValueAnimator animation){
                if( bm_glare != null ){
                    pos_x = Math.round( 1f*size.x*4*(float)animation.getAnimatedValue() )- bm_glare.getWidth();
                    invalidateSelf();

                }
            }
        });
    }
    
    void onResume(){
        animator.start();
    }

    void onPause(){
        animator.cancel();
    }

    @Override
    public void draw(Canvas canvas){
        if( canvas.getWidth() != size.x || canvas.getHeight() != size.y ){
            size.x = canvas.getWidth(); size.y = canvas.getHeight();
            lg = new LinearGradient( 0,0, size.x, size.y, color0, color1, Shader.TileMode.CLAMP );
            path.reset(); path.addRoundRect(0,0, size.x, size.y, size.y/2, size.y/2, Path.Direction.CW );
            if( bm_glare != null ){bm_glare.recycle();}
            bm_glare = Bitmap.createBitmap( size.y, size.y, Bitmap.Config.ARGB_8888 );
            LinearGradient lg_glide = new LinearGradient( size.y*-0.25f,0, size.y*1.25f, size.y, new int[]{0, 0xc0ffffff, 0xc0ffffff, 0 }, new float[]{0.45f,0.4975f,0.5025f,0.55f}, Shader.TileMode.CLAMP );
            Canvas canvas1 = new Canvas(bm_glare);
            paint.setShader( lg_glide );
            canvas1.drawPaint( paint );
            pos_x = -bm_glare.getWidth();
        }
        paint.setShader( lg );
        canvas.clipPath( path );
        canvas.drawPaint( paint );
        canvas.drawBitmap( bm_glare, pos_x,0,null);
    }

    @Override
    public void setAlpha(int alpha){

    }

    @Override
    public void setColorFilter(ColorFilter colorFilter){

    }

    @Override
    public int getOpacity(){
        return PixelFormat.OPAQUE;
    }
}

Блик

→ Ссылка