Testo rotante Android: utilizzo dynamiclayout.draw (canvas) ma non si anima lungo il percorso e non posso usare canvas.drawTextOnPath (dynamiclayout)


11

Sto usando la mia versione di https://github.com/mdg-iitr/RotatingText per mostrare un widget di testo rotante. In questo GitHub è disponibile un video che ti consente di vedere l'animazione. L'idea è di creare file di parole. Le righe vengono visualizzate riga dopo riga. L'intera riga ruota (così fanno le sue parole). Una riga viene visualizzata dopo la riga precedente al termine dell'animazione di rotazione di quest'ultima.

Il mio problema

Uso a DynamicLayoutper mostrare le righe di testo. Ricorda: le righe devono ruotare.

Il mio problema è: ovviamente, non posso usare il metodo canvas.drawTextOnPath(dynamicLayoutObject). Quindi quello che faccio è: dynamicLayoutObjec.draw(canvas);. Ma allora non c'è animazione. In effetti, il testo (quindi quello DynamicLayoutche lo contiene) deve ruotare.

Risultato atteso

Il DynamicLayout(in effetti, il suo testo) deve essere animato (una rotazione). La rotazione può essere trovata nell'illustrazione del repository originale di Github fornita all'inizio di questa domanda SO ( https://github.com/mdg-iitr/RotatingText ).

La mia domanda

Non so come far DynamicLayoutruotare il mio (e / o il suo testo) lungo il mio percorso.

Esempio minimo e testabile

Ho modificato la libreria originale di RotatingText 8 mesi fa circa. per semplificarlo (meno classi, meno metodi, nessun metodo inutilizzato, ecc.). In effetti, ho solo due classi:

  1. RotatingTextSwitcher, che è il widget XML

  2. E Rotatable, che contiene l'array di stringhe da ruotare.

  3. Un layout .XML contenente il widget XML RotatingTextSwitcherper testarlo

  4. A Fragmentgonfiare il layout precedentemente citato, impostare le parole di ogni riga rotante e mostrarle.

Per testarlo, crea un'attività che mostri il frammento indicato di seguito, che a sua volta utilizza le altre fonti, presentate sopra.

Classe ruotabile

import android.graphics.Path;
import android.view.animation.Interpolator;

public class Rotatable {

    private final String[] text;
    private final int update_duration;
    private int animation_duration;
    private Path path_in, path_out;
    private int currentWordNumber;
    private Interpolator interpolator;

    public Rotatable(int update_duration, int animation_duration, Interpolator interpolator, String... text) {
        this.update_duration = update_duration;
        this.animation_duration = animation_duration;
        this.text = text;
        this.interpolator = interpolator;
        currentWordNumber = -1;
    }

    private int nextWordNumber() {
        currentWordNumber = (currentWordNumber + 1) % text.length;
        return currentWordNumber;
    }

    String nextWord() {
        return text[nextWordNumber()];
    }

    Path getPathIn() {
        return path_in;
    }
    void setPathIn(Path path_in) {
        this.path_in = path_in;
    }
    Path getPathOut() {
        return path_out;
    }
    void setPathOut(Path path_out) {
        this.path_out = path_out;
    }

    int getUpdateDuration() {
        return update_duration;
    }

    int getAnimationDuration() {
        return animation_duration;
    }

    Interpolator getInterpolator() { return interpolator; }
}

Classe RotatingTextSwitcher

package libs.rotating_text;

import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.DynamicLayout;
import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;

import androidx.appcompat.widget.AppCompatTextView;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

import androidx.annotation.Nullable;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class RotatingTextSwitcher extends AppCompatTextView {

    Disposable disposable;

    private TextPaint textPaint = new TextPaint();
    private String text = "", old_text = "";
    SpannableStringBuilder base = new SpannableStringBuilder(text);
    SpannableStringBuilder base_old = new SpannableStringBuilder(old_text);
    private DynamicLayout layout = new DynamicLayout(base, textPaint,500, Layout.Alignment.ALIGN_CENTER,1.0F,0.0F,true);
    private DynamicLayout layout_old = new DynamicLayout(base_old, textPaint,500, Layout.Alignment.ALIGN_CENTER,1.0F,0.0F,true);

    private Rotatable rotatable;
    private Paint paint;
    private Path path_in, path_out;

    public RotatingTextSwitcher(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        paint = getPaint();
        paint.setAntiAlias(true);
    }

    public void setRotatable(Rotatable rotatable) {
        this.rotatable = rotatable;
        initialize();
    }

    private void initialize() {
        text = rotatable.nextWord();
        base.clear();
        base.append(text);
        old_text = text;
        base_old.clear();
        base_old.append(old_text);
        setUpPath();
        setDisposable();
        scheduleUpdateTextTimer();
    }

    private void setDisposable() {
        disposable = Observable.interval(1000 / 60, TimeUnit.MILLISECONDS, Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) {
                        invalidate();
                    }
                });
    }

    private void setUpPath() {
        post(new Runnable() {
            @Override
            public void run() {
                path_in = new Path();
                path_in.moveTo(0.0f, getHeight() - paint.getFontMetrics().bottom);
                path_in.lineTo(getWidth(), getHeight() - paint.getFontMetrics().bottom);
                rotatable.setPathIn(path_in);

                path_out = new Path();
                path_out.moveTo(0.0f, (2 * getHeight()) - paint.getFontMetrics().bottom);
                path_out.lineTo(getWidth(), (2 * getHeight()) - paint.getFontMetrics().bottom);
                rotatable.setPathOut(path_out);
            }
        });
    }

    private void scheduleUpdateTextTimer() {
        Timer update_text_timer = new Timer();
        update_text_timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                ((Activity) getContext()).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        animateInHorizontal();
                        animateOutHorizontal();
                        old_text = text;
                        base_old.clear();
                        base_old.append(old_text);
                        text = rotatable.nextWord();
                        base.clear();
                        base.append(text);
                    }
                });
            }
        }, rotatable.getUpdateDuration(), rotatable.getUpdateDuration());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
        float size = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 32, metrics);
        textPaint.setTextSize(size);

        if (rotatable.getPathIn() != null) {
            layout.draw(canvas);
            //canvas.drawTextOnPath(text, rotatable.getPathIn(), 0.0f, 0.0f, paint);
        }
        if (rotatable.getPathOut() != null) {
            layout_old.draw(canvas);
            //canvas.drawTextOnPath(old_text, rotatable.getPathOut(), 0.0f, 0.0f, paint);
        }
        setHeight(layout.getHeight() + layout_old.getHeight());
    }

    private void animateInHorizontal() {
        ValueAnimator animator = ValueAnimator.ofFloat(0.0f, getHeight());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                path_in = new Path();
                path_in.moveTo(0.0f, (Float) valueAnimator.getAnimatedValue() - paint.getFontMetrics().bottom);
                path_in.lineTo(getWidth(), (Float) valueAnimator.getAnimatedValue() - paint.getFontMetrics().bottom);
                rotatable.setPathIn(path_in);
            }
        });
        animator.setInterpolator(rotatable.getInterpolator());
        animator.setDuration(rotatable.getAnimationDuration());
        animator.start();
    }

    private void animateOutHorizontal() {
        ValueAnimator animator = ValueAnimator.ofFloat(getHeight(), getHeight() * 2.0f);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                path_out = new Path();
                path_out.moveTo(0.0f, (Float) valueAnimator.getAnimatedValue() - paint.getFontMetrics().bottom);
                path_out.lineTo(getWidth(), (Float) valueAnimator.getAnimatedValue() - paint.getFontMetrics().bottom);
                rotatable.setPathOut(path_out);
            }
        });
        animator.setInterpolator(rotatable.getInterpolator());
        animator.setDuration(rotatable.getAnimationDuration());
        animator.start();
    }


}

Un layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <libs.rotating_text.RotatingTextSwitcher
        android:id="@+id/textView_presentation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="50dp"
        android:textSize="35sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

Un frammento

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.example.androidframework.R;

import libs.rotating_text.Rotatable;
import libs.rotating_text.RotatingTextSwitcher;

public class FragmentHomeSlide extends Fragment {

    private View inflated;
    private int drawable_id;
    private String[] text_presentation;

    @Override
    public void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        assert getArguments() != null;
        text_presentation = new String[];
        text_presentation[0] = "One row is set up with several words";
        text_presentation[1] = "This is another row";
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
        inflated = inflater.inflate(R.layout.home_slide, container, false);
        setWidgets();
        return inflated;
    }

    private void setWidgets() {    
        final RotatingTextSwitcher rotating_presentation = inflated.findViewById(R.id.textView_presentation);
        rotating_presentation.setRotatable(new Rotatable(1000, 500, new AccelerateInterpolator(), text_presentation));
    }
}

1
Hai descritto il problema, ma non hai detto qual è la tua soluzione prevista. Cosa ti piacerebbe vedere quando la riga ha troppi simboli?
Azizbekian

1
non è troppo, signore. Ho appena esaminato la tua domanda e non sono riuscito a capire il tuo requisito. L'ho chiesto per chiarire anche altri lettori. Penserò al problema e mi verrà in mente una risposta se ne trovo qualcuno. Grazie.
Azizbekian

@azizbekian Ho progredito molto nella risoluzione del mio problema. Ora penso di sapere cosa non andava: non l'ho usato DynamicLayout. Quindi, ora lo uso ... ma non riesco a farlo ruotare lungo il percorso. Ho modificato la domanda. La taglia è ancora disponibile :-).
JarsOfJam-Scheduler

Risposte:


0

la mia idea sta cambiando l'input con i limiti del tuo problema ... per esempio se riesci a scrivere 20 caratteri, cambia correttamente gli array di stringhe in linee con 20 caratteri o meno.

aggiungi questo codice al costruttore ruotabile

    ArrayList<String> newttext = new ArrayList<>();
    for (int i = 0; i < text.length; i++) {
        if (text[i].length() > 20){ // 20 is number characters
            ArrayList<String> strings = myCutter(text[i]);
            newttext.addAll(strings);
        }else{
            newttext.add(text[i]);
        }
    }

la linea Codice taglierina

    public ArrayList<String> myCutter(String s) {
    String trueLine = "";
    ArrayList<String> result = new ArrayList<>();
    if (s.length() > 20) {
        String[] split = s.split(" ");
        for (int i = 0; i < split.length; i++) {
            if (trueLine.length() + split[i].length() < 20) {
                trueLine = trueLine + " " + split[i];
            } else {
                result.add(trueLine);
                trueLine = "";
            }
        }
    } else {
        result.add(s);
    }
    return result;
}

Ho progredito molto nella risoluzione del mio problema. Ora penso di sapere cosa non andava: non l'ho usato DynamicLayout. Quindi, ora lo uso ... ma non riesco a farlo ruotare lungo il percorso. Ho modificato la domanda. La taglia è ancora disponibile :-).
JarsOfJam-Scheduler
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.