资源下载https://yunpan.cn/cBAfAPXP3dSZi 访问密码 7238
import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.os.Build; import android.view.animation.LinearInterpolator; /** * Titanic * User: romainpiel * Date: 14/03/2014 * Time: 09:34 */ public class Titanic { private AnimatorSet animatorSet; private Animator.AnimatorListener animatorListener; public Animator.AnimatorListener getAnimatorListener() { return animatorListener; } public void setAnimatorListener(Animator.AnimatorListener animatorListener) { this.animatorListener = animatorListener; } public void start(final TitanicTextView textView) { final Runnable animate = new Runnable() { @Override public void run() { textView.setSinking(true); // horizontal animation. 200 = wave.png width ObjectAnimator maskXAnimator = ObjectAnimator.ofFloat(textView, "maskX", 0, 200); maskXAnimator.setRepeatCount(ValueAnimator.INFINITE); maskXAnimator.setDuration(1000); maskXAnimator.setStartDelay(0); int h = textView.getHeight(); // vertical animation // maskY = 0 -> wave vertically centered // repeat mode REVERSE to go back and forth ObjectAnimator maskYAnimator = ObjectAnimator.ofFloat(textView, "maskY", h/2, - h/2); maskYAnimator.setRepeatCount(ValueAnimator.INFINITE); maskYAnimator.setRepeatMode(ValueAnimator.REVERSE); maskYAnimator.setDuration(10000); maskYAnimator.setStartDelay(0); // now play both animations together animatorSet = new AnimatorSet(); animatorSet.playTogether(maskXAnimator, maskYAnimator); animatorSet.setInterpolator(new LinearInterpolator()); animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { textView.setSinking(false); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { textView.postInvalidate(); } else { textView.postInvalidateOnAnimation(); } animatorSet = null; } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); if (animatorListener != null) { animatorSet.addListener(animatorListener); } animatorSet.start(); } }; if (!textView.isSetUp()) { textView.setAnimationSetupCallback(new TitanicTextView.AnimationSetupCallback() { @Override public void onSetupAnimation(final TitanicTextView target) { animate.run(); } }); } else { animate.run(); } } public void cancel() { if (animatorSet != null) { animatorSet.cancel(); } } }
import android.content.Context; import android.graphics.Typeface; import android.util.Log; import java.util.Hashtable; public class Typefaces { private static final String TAG = "Typefaces"; private static final Hashtablecache = new Hashtable (); public static Typeface get(Context c, String assetPath) { synchronized (cache) { if (!cache.containsKey(assetPath)) { try { Typeface t = Typeface.createFromAsset(c.getAssets(), assetPath); cache.put(assetPath, t); } catch (Exception e) { Log.e(TAG, "Could not get typeface '" + assetPath + "' because " + e.getMessage()); return null; } } return cache.get(assetPath); } } }
package tests.bwie.com.mygridview.view; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.TextView; import tests.bwie.com.mygridview.R; /** * Titanic * romainpiel * 13/03/2014 */ public class TitanicTextView extends TextView { public interface AnimationSetupCallback { public void onSetupAnimation(TitanicTextView titanicTextView); } // callback fired at first onSizeChanged private AnimationSetupCallback animationSetupCallback; // wave shader coordinates private float maskX, maskY; // if true, the shader will display the wave private boolean sinking; // true after the first onSizeChanged private boolean setUp; // shader containing a repeated wave private BitmapShader shader; // shader matrix private Matrix shaderMatrix; // wave drawable private Drawable wave; // (getHeight() - waveHeight) / 2 private float offsetY; public TitanicTextView(Context context) { super(context); init(); } public TitanicTextView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public TitanicTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { shaderMatrix = new Matrix(); } public AnimationSetupCallback getAnimationSetupCallback() { return animationSetupCallback; } public void setAnimationSetupCallback(AnimationSetupCallback animationSetupCallback) { this.animationSetupCallback = animationSetupCallback; } public float getMaskX() { return maskX; } public void setMaskX(float maskX) { this.maskX = maskX; invalidate(); } public float getMaskY() { return maskY; } public void setMaskY(float maskY) { this.maskY = maskY; invalidate(); } public boolean isSinking() { return sinking; } public void setSinking(boolean sinking) { this.sinking = sinking; } public boolean isSetUp() { return setUp; } @Override public void setTextColor(int color) { super.setTextColor(color); createShader(); } @Override public void setTextColor(ColorStateList colors) { super.setTextColor(colors); createShader(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); createShader(); if (!setUp) { setUp = true; if (animationSetupCallback != null) { animationSetupCallback.onSetupAnimation(TitanicTextView.this); } } } /** * Create the shader * draw the wave with current color for a background * repeat the bitmap horizontally, and clamp colors vertically */ private void createShader() { if (wave == null) { wave = getResources().getDrawable(R.drawable.wave); } int waveW = wave.getIntrinsicWidth(); int waveH = wave.getIntrinsicHeight(); Bitmap b = Bitmap.createBitmap(waveW, waveH, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b); c.drawColor(getCurrentTextColor()); wave.setBounds(0, 0, waveW, waveH); wave.draw(c); shader = new BitmapShader(b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); getPaint().setShader(shader); offsetY = (getHeight() - waveH) / 2; } @Override protected void onDraw(Canvas canvas) { // modify text paint shader according to sinking state if (sinking && shader != null) { // first call after sinking, assign it to our paint if (getPaint().getShader() == null) { getPaint().setShader(shader); } // translate shader accordingly to maskX maskY positions // maskY is affected by the offset to vertically center the wave shaderMatrix.setTranslate(maskX, maskY + offsetY); // assign matrix to invalidate the shader shader.setLocalMatrix(shaderMatrix); } else { getPaint().setShader(null); } super.onDraw(canvas); } }
xml中
"1.0" encoding="utf-8"?>"http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="tests.bwie.com.mygridview.ShuiBoTextViewActivity"> <tests.bwie.com.mygridview.view.TitanicTextView android:id="@+id/my_text_view" android:text="Loading" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:textColor="#212121" android:textSize="70sp" android:paddingLeft="5dp" android:paddingRight="5dp"/>
activity中
TitanicTextView tv = (TitanicTextView) findViewById(R.id.my_text_view); // set fancy typeface tv.setTypeface(Typefaces.get(this, "Satisfy-Regular.ttf")); // start animation new Titanic().start(tv);