// Path: htextview-library/src/main/java/com/hanks/htextview/util/CharacterUtils.java
// public class CharacterUtils {
// 
//     public static List<CharacterDiffResult> diff(CharSequence oldText, CharSequence newText) {
// 
//         List<CharacterDiffResult> differentList = new ArrayList<>();
//         Set<Integer> skip = new HashSet<>();
// 
//         for (int i = 0; i < oldText.length(); i++) {
//             char c = oldText.charAt(i);
//             for (int j = 0; j < newText.length(); j++) {
//                 if (!skip.contains(j) && c == newText.charAt(j)) {
//                     skip.add(j);
//                     CharacterDiffResult different = new CharacterDiffResult();
//                     different.c = c;
//                     different.fromIndex = i;
//                     different.moveIndex = j;
//                     differentList.add(different);
//                     break;
//                 }
//             }
//         }
//         return differentList;
//     }
// 
//     public static int needMove(int index, List<CharacterDiffResult> differentList) {
//         for (CharacterDiffResult different : differentList) {
//             if (different.fromIndex == index) {
//                 return different.moveIndex;
//             }
//         }
//         return -1;
//     }
// 
//     public static boolean stayHere(int index, List<CharacterDiffResult> differentList) {
//         for (CharacterDiffResult different : differentList) {
//             if (different.moveIndex == index) {
//                 return true;
//             }
//         }
//         return false;
//     }
// 
//     /**
//      * @return
//      */
//     public static float getOffset(int from, int move, float progress, float startX, float oldStartX, float[] gaps, float[] oldGaps) {
// 
//         float dist = startX;
//         for (int i = 0; i < move; i++) {
//             dist += gaps[i];
//         }
// 
//         float cur = oldStartX;
//         for (int i = 0; i < from; i++) {
//             cur += oldGaps[i];
//         }
// 
//         return cur + (dist - cur) * progress;
// 
//     }
// 
// }


import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.animation.BounceInterpolator;
import com.hanks.htextview.R;
import com.hanks.htextview.util.CharacterUtils;
import java.lang.reflect.Field;
            dstWidth = mTextWidth * 1.2f;
            if (dstWidth < 404f) dstWidth = 404f;
            mMatrix.postScale(dstWidth / (float) smokes[0].getWidth(), 1f);
        }
    }

    @Override
    protected void animatePrepare(CharSequence text) {

        Rect bounds = new Rect();
        mPaint.getTextBounds(mText.toString(), 0, mText.length(), bounds);
        mTextHeight = bounds.height();
        mTextWidth = bounds.width();
    }

    @Override
    protected void drawFrame(Canvas canvas) {
        float offset = startX;
        float oldOffset = oldStartX;

        int maxLength = Math.max(mText.length(), mOldText.length());

        float percent = progress;
        boolean showSmoke = false;
        for (int i = 0; i < maxLength; i++) {

            // draw old text
            if (i < mOldText.length()) {

                mOldPaint.setTextSize(mTextSize);
// Path: htextview-library/src/main/java/com/hanks/htextview/util/CharacterUtils.java
// public class CharacterUtils {
// 
//     public static List<CharacterDiffResult> diff(CharSequence oldText, CharSequence newText) {
// 
//         List<CharacterDiffResult> differentList = new ArrayList<>();
//         Set<Integer> skip = new HashSet<>();
// 
//         for (int i = 0; i < oldText.length(); i++) {
//             char c = oldText.charAt(i);
//             for (int j = 0; j < newText.length(); j++) {
//                 if (!skip.contains(j) && c == newText.charAt(j)) {
//                     skip.add(j);
//                     CharacterDiffResult different = new CharacterDiffResult();
//                     different.c = c;
//                     different.fromIndex = i;
//                     different.moveIndex = j;
//                     differentList.add(different);
//                     break;
//                 }
//             }
//         }
//         return differentList;
//     }
// 
//     public static int needMove(int index, List<CharacterDiffResult> differentList) {
//         for (CharacterDiffResult different : differentList) {
//             if (different.fromIndex == index) {
//                 return different.moveIndex;
//             }
//         }
//         return -1;
//     }
// 
//     public static boolean stayHere(int index, List<CharacterDiffResult> differentList) {
//         for (CharacterDiffResult different : differentList) {
//             if (different.moveIndex == index) {
//                 return true;
//             }
//         }
//         return false;
//     }
// 
//     /**
//      * @return
//      */
//     public static float getOffset(int from, int move, float progress, float startX, float oldStartX, float[] gaps, float[] oldGaps) {
// 
//         float dist = startX;
//         for (int i = 0; i < move; i++) {
//             dist += gaps[i];
//         }
// 
//         float cur = oldStartX;
//         for (int i = 0; i < from; i++) {
//             cur += oldGaps[i];
//         }
// 
//         return cur + (dist - cur) * progress;
// 
//     }
// 
// }


// Path: htextview-library/src/main/java/com/hanks/htextview/animatetext/AnvilText.java
import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.animation.BounceInterpolator;
import com.hanks.htextview.R;
import com.hanks.htextview.util.CharacterUtils;
import java.lang.reflect.Field;

            dstWidth = mTextWidth * 1.2f;
            if (dstWidth < 404f) dstWidth = 404f;
            mMatrix.postScale(dstWidth / (float) smokes[0].getWidth(), 1f);
        }
    }

    @Override
    protected void animatePrepare(CharSequence text) {

        Rect bounds = new Rect();
        mPaint.getTextBounds(mText.toString(), 0, mText.length(), bounds);
        mTextHeight = bounds.height();
        mTextWidth = bounds.width();
    }

    @Override
    protected void drawFrame(Canvas canvas) {
        float offset = startX;
        float oldOffset = oldStartX;

        int maxLength = Math.max(mText.length(), mOldText.length());

        float percent = progress;
        boolean showSmoke = false;
        for (int i = 0; i < maxLength; i++) {

            // draw old text
            if (i < mOldText.length()) {

                mOldPaint.setTextSize(mTextSize);
                int move = CharacterUtils.needMove(i, differentList);