Văn bản xoay vòng của Android: Tôi sử dụng Dynamiclayout.draw (canvas) nhưng nó không hoạt động dọc theo đường dẫn và không thể sử dụng canvas.drawTextOnPath (Dynamiclayout)


11

Tôi đang sử dụng phiên bản https://github.com/mdg-iitr/RotatingText của riêng mình để hiển thị tiện ích văn bản xoay. Một video có sẵn trong GitHub này, cho phép bạn xem hoạt hình. Ý tưởng là để thiết lập các hàng từ. Các hàng được hiển thị hàng sau hàng. Toàn bộ hàng xoay (vì vậy làm từ của nó). Một hàng được hiển thị sau hàng trước khi hoạt ảnh xoay của hàng sau kết thúc.

Vấn đề của tôi

Tôi sử dụng một DynamicLayoutđể hiển thị các hàng văn bản. Hãy nhớ rằng: các hàng phải xoay.

Vấn đề của tôi là: rõ ràng, tôi không thể sử dụng phương pháp này canvas.drawTextOnPath(dynamicLayoutObject). Vì vậy, những gì tôi làm là : dynamicLayoutObjec.draw(canvas);. Nhưng không có hoạt hình nào cả. Thật vậy, văn bản (vì vậy DynamicLayoutcó chứa nó) phải xoay.

Kết quả mong đợi

Các DynamicLayout(trong thực tế, văn bản của nó) phải được hoạt hình (vòng xoay). Xoay có thể được tìm thấy trong hình minh họa của repo gốc Github được đưa ra ở đầu Câu hỏi SO này ( https://github.com/mdg-iitr/RotatingText ).

Câu hỏi của tôi

Tôi không biết làm thế nào để làm cho DynamicLayout(và / hoặc văn bản của nó) xoay dọc theo đường dẫn của tôi.

Ví dụ tối thiểu và có thể kiểm tra

Tôi đã sửa đổi thư viện Xoay chiều ban đầu cách đây 8 tháng. để đơn giản hóa nó (ít lớp hơn, ít phương thức hơn, không có phương thức không sử dụng, v.v.). Thật vậy, tôi chỉ có hai lớp:

  1. RotatingTextSwitcher, đó là tiện ích XML

  2. Rotatable, trong đó có chứa các chuỗi được xoay.

  3. Bố cục .XML chứa tiện ích XML RotatingTextSwitcherđể kiểm tra nó

  4. Một Fragmentbố cục được đề cập trước đó, thiết lập các từ của mỗi hàng xoay và hiển thị chúng.

Để kiểm tra nó, hãy tạo một hoạt động hiển thị đoạn được đưa ra dưới đây, lần lượt sử dụng các nguồn khác, được trình bày ở trên.

Lớp học xoay

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; }
}

Lớp Xoay

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();
    }


}

Bố cục

<?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>

Một mảnh vỡ

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
Bạn đã mô tả vấn đề, nhưng chưa nói giải pháp mong đợi của bạn là gì. Bạn muốn thấy gì khi hàng có quá nhiều ký hiệu?
azizbekian

1
nó không quá nhiều, thưa ngài. Tôi vừa đi qua câu hỏi của bạn và không thể hiểu yêu cầu của bạn. Tôi đã hỏi nó để làm cho nó rõ ràng cho các độc giả khác. Tôi sẽ suy nghĩ về vấn đề này và sẽ đưa ra câu trả lời nếu tôi tìm thấy một số. Cảm ơn.
azizbekian

@azizbekian Tôi đã tiến bộ rất nhiều trong việc giải quyết vấn đề của mình. Bây giờ tôi nghĩ rằng tôi biết những gì đã sai: Tôi đã không sử dụng DynamicLayout. Vì vậy, bây giờ tôi sử dụng nó ... nhưng tôi không thể làm cho nó xoay dọc theo đường dẫn. Tôi đã chỉnh sửa câu hỏi. Tiền thưởng vẫn có sẵn :-).
JarsOfJam-Lập lịch

Câu trả lời:


0

ý tưởng của tôi là thay đổi đầu vào với giới hạn vấn đề của bạn ... ví dụ: nếu bạn có thể viết 20 Chars thay đổi chính xác các mảng chuỗi thành các dòng có 20 Chars trở xuống ..

thêm mã này vào hàm tạo có thể xoay

    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]);
        }
    }

Mã cắt dòng

    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;
}

Tôi đã tiến bộ rất nhiều trong việc giải quyết vấn đề của mình. Bây giờ tôi nghĩ rằng tôi biết những gì đã sai: Tôi đã không sử dụng DynamicLayout. Vì vậy, bây giờ tôi sử dụng nó ... nhưng tôi không thể làm cho nó xoay dọc theo đường dẫn. Tôi đã chỉnh sửa câu hỏi. Tiền thưởng vẫn có sẵn :-).
JarsOfJam-Lập lịch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.