使用他人的项目
在github上,有很多大佬开源了自己的项目,通过使用他们的项目,来快速部署自己项目中的其中一个功能,这里使用我这次项目中的Titanic for Android来作为教学。
使用他人项目的时候,请务必标注来源,这是对原作者的尊重,同时也是开源社区需要自觉遵守的制度。
本次使用开源项目Titanic for Android —— romainpiel
这是一个美化字体的项目,通过观察README可以知道如何使用,首先我们需要将项目克隆到本地方便查看和复制。
通过使用git clone进行克隆,在code按钮中复制git地址然后进行克隆。
git clone https://github.com/romainpiel/Titanic.git
具体的git教程可以看我的另一个笔记。
克隆完成后,分析项目,找到关键的java代码,复制到自己的项目,然后按照README教程进行调用。
在这个项目中,library里是核心java代码,需要将Titanic.java和TitanicTextView.ava复制到自己的项目中,其中Titanic代码打开后是这样的:
package com.romainpiel.titanic.library;
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();
}
}
}
通过观察代码,发现这个文件没有继承任何类,代表这是一个功能类,同时通过详细阅读代码,发现这是用来控制美化字体的动态效果,通过着色器让文字的遮罩按照波浪的样子往上移动。
然后是TitanicTextView.ava,不难发现TextView是Android的一个组件,打开代码后,发现果然如此:
package com.romainpiel.titanic.library;
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;
/**
* 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);
}
}
这个类继承了TextView,这代表如果要使用这个文件,则是导入组件,README中也是这样告诉你的。
How to use
Add a TitanicTextView
to your layout:
<com.romainpiel.titanic.TitanicTextView
android:id="@+id/titanic_tv"
android:text="@string/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#212121"
android:textSize="70sp"/>
至此最关键的部分已经搞定,复制文件的时候需要注意层级关系,同时复制完成后可能会遇到报错的情况,这是因为自己的项目一些引入的路径可能不对,需要重新更改下路径,比如官方给出的com.romainpiel.titanic.TitanicTextView在自己的项目中并不对,因为我的层级不是这样的,对我而言,则是使用:com.romainpiel.titanic.library.TitanicTextView,举一反三,其他也是如此。
注意将所有用到的文件都复制进去,这里还有一张资源图片就不过多讲了。
至此,已经成功使用了他人的项目,一些细节的修改可以通过阅读代码来做到。