1
0
mirror of https://gitee.com/51danju/workclock.git synced 2025-07-16 13:57:29 +08:00

增加 计时、倒计时,时间变更动画和几个指针样式

This commit is contained in:
wushunlian 2019-03-16 18:14:28 +08:00
parent 6e9ddaa968
commit 45a2ab6701
32 changed files with 1755 additions and 685 deletions

View File

@ -12,8 +12,6 @@ import android.os.PowerManager;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.text.Spannable;
import android.text.SpannableString;
import android.util.Log;
import android.view.GestureDetector;
import android.view.KeyEvent;
@ -40,6 +38,7 @@ import com.luck.picture.lib.entity.LocalMedia;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
@ -63,13 +62,14 @@ import clock.socoolby.com.clock.widget.animatorview.animator.BubbleWhirlPoolAnim
import clock.socoolby.com.clock.widget.animatorview.animator.CarrouselAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.ClockAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.DotsLineAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.MagicLineAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.PhaserBallAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.SawtoothAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.Wave3DAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.AbstractClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.CircleClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.CircleTwoClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.HelixClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.HexagonalClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.OctagonalClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.OvalClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.SquareClock;
import clock.socoolby.com.clock.widget.animatorview.animator.textanimator.EZLedAnimator;
@ -77,7 +77,6 @@ import clock.socoolby.com.clock.widget.animatorview.animator.FireAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.FireworkAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.FluorescenceAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.RainAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.RippleAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.SkyAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.SnowAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.StarFallAnimator;
@ -85,7 +84,6 @@ import clock.socoolby.com.clock.widget.animatorview.animator.VorolayAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.WaterAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.WindmillAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.textanimator.EvaporateTextAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.textanimator.PathEffectTextAnimator;
import clock.socoolby.com.clock.widget.textview.AutoScrollTextView;
import clock.socoolby.com.clock.widget.textview.DigitTextView;
@ -311,6 +309,14 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
private Integer foregroundColor;
private FrameLayout mainBackground;
private ImageButton tv_break;
private Date countingDateTimeBase =null;
private ShowTimeType showTimeType=ShowTimeType.TIME;
public enum ShowTimeType{
TIME,COUNTING_DOWN,COUNTING;
}
public void setWeather(WeatherResponse weather) {
@ -378,6 +384,21 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
}
});
tv_break=findViewById(R.id.tv_break);
tv_break.setOnClickListener(this);
tv_break.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if(handUpAbla){
if(showTimeType==ShowTimeType.COUNTING_DOWN)
setCurrentShowTimeType(ShowTimeType.TIME);
else
setCurrentShowTimeType(ShowTimeType.COUNTING_DOWN);
}
return true;
}
});
tv_handup=findViewById(R.id.tv_hand);
tv_handup.setOnClickListener(this);
tv_handup.setOnLongClickListener(new View.OnLongClickListener() {
@ -702,6 +723,8 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
tv_hand_time.setTextColor(color);
tv_hours_system.setColorFilter(color);
tv_background_image_hand.setColorFilter(color);
tv_break.setColorFilter(color);
}
protected void setBackGroundColor(Integer color){
@ -765,6 +788,13 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
}
screenLock(!screenLock);
break;
case R.id.tv_break:
if(showTimeType!=ShowTimeType.COUNTING){
setCurrentShowTimeType(ShowTimeType.COUNTING);
}else{
setCurrentShowTimeType(ShowTimeType.TIME);
}
break;
case R.id.tv_descript:
setDiscript(SettingActivity.roundAutoQuotes());
break;
@ -799,6 +829,14 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
}
}
public void setCurrentShowTimeType(ShowTimeType type){
switch (type){
case COUNTING:
countingDateTimeBase =new Date();
}
showTimeType=type;
}
public void screenLock(boolean locked){
screenLock=locked;
@ -879,6 +917,8 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
tv_foreground_color.setVisibility(View.GONE);
tv_foreground_color1.setVisibility(View.GONE);
tv_background_image_hand.setVisibility(View.GONE);
tv_break.setVisibility(View.GONE);
}else{
if(clockView.isRunning()) {
//clockView.setAnimator(null);
@ -893,6 +933,7 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
tv_handup_image.setVisibility(View.VISIBLE);
tv_handup.setVisibility(View.VISIBLE);
tv_break.setVisibility(View.VISIBLE);
if(prevMode==MODE_HANDUP)
switchMode(MODE_NORMAL);
@ -914,7 +955,7 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
DotsLineAnimator dotsLineAnimator;
WaterAnimator waterAnimator;
FireAnimator fireAnimator;
RippleAnimator rippleAnimator;
SawtoothAnimator sawtoothAnimator;
WindmillAnimator windmillAnimator;
VorolayAnimator vorolayAnimator;
EZLedAnimator eZLedAnimator;
@ -922,6 +963,7 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
PhaserBallAnimator phaserBallAnimator;
CarrouselAnimator carrouselAnimator;
Wave3DAnimator wave3DAnimator;
MagicLineAnimator magicLineAnimator;
public void changeBackGroundAnimator(int index){
switch(index){
case 0:
@ -942,7 +984,7 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
backGroundAnimator= phaserBallAnimator;
backGroundAnimator.setRandColor(true);
break;
case 3:
case 20:
if(rainAnimator==null) {
rainAnimator = new RainAnimator();
rainAnimator.init(animatorView.getContext(),animatorView);
@ -1095,7 +1137,7 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
backGroundAnimator= dotsLineAnimator;
backGroundAnimator.setRandColor(true);
break;
case 20:
case 3:
if(waterAnimator ==null) {
waterAnimator = new WaterAnimator();
waterAnimator.init(animatorView.getContext(),animatorView);
@ -1123,12 +1165,12 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
backGroundAnimator.setRandColor(false);
break;
case 23:
if(rippleAnimator ==null) {
rippleAnimator = new RippleAnimator();
rippleAnimator.init(animatorView.getContext(),animatorView);
rippleAnimator.setColor(foregroundColor);
if(sawtoothAnimator ==null) {
sawtoothAnimator = new SawtoothAnimator();
sawtoothAnimator.init(animatorView.getContext(),animatorView);
sawtoothAnimator.setColor(foregroundColor);
}
backGroundAnimator= rippleAnimator;
backGroundAnimator= sawtoothAnimator;
backGroundAnimator.setRandColor(true);
break;
case 24:
@ -1158,7 +1200,7 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
backGroundAnimator= carrouselAnimator;
backGroundAnimator.setRandColor(true);
break;
case 1:
case 27:
if(wave3DAnimator ==null) {
wave3DAnimator = new Wave3DAnimator();
wave3DAnimator.init(animatorView.getContext(),animatorView);
@ -1167,6 +1209,24 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
backGroundAnimator= wave3DAnimator;
backGroundAnimator.setRandColor(true);
break;
case 28:
if(magicLineAnimator ==null) {
magicLineAnimator = new MagicLineAnimator();
magicLineAnimator.init(animatorView.getContext(),animatorView);
magicLineAnimator.setColor(foregroundColor);
}
backGroundAnimator= magicLineAnimator;
backGroundAnimator.setRandColor(true);
break;
case 1:
if(magicLineAnimator ==null) {
magicLineAnimator = new MagicLineAnimator();
magicLineAnimator.init(animatorView.getContext(),animatorView);
magicLineAnimator.setColor(foregroundColor);
}
backGroundAnimator= magicLineAnimator;
backGroundAnimator.setRandColor(false);
break;
case 60:
if(evaporateTextAnimator ==null) {
@ -1205,7 +1265,7 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
clockAnimator = new ClockAnimator();
clockAnimator.init(clockView.getContext(),clockView);
clockAnimator.setColor(foregroundColor);
if(index>4)
if(index>5)
currentClockAnimatorIndex=index=0;
switch (index) {
@ -1218,13 +1278,13 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
case 1:
clockAnimator.setClock(new SquareClock());
break;
//case 3:
// clockAnimator.setClock(new OctagonalClock());
// break;
case 3:
clockAnimator.setClock(new HexagonalClock());
clockAnimator.setClock(new CircleTwoClock());
break;
case 4:
clockAnimator.setClock(new HexagonalClock());
break;
case 5:
clockAnimator.setClock(new HelixClock());
break;
default:
@ -1245,6 +1305,8 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
}else{
this.tv_handup.setColorFilter(R.color.colorPrimaryDark);
this.tv_hand_time.setVisibility(View.GONE);
if(showTimeType==ShowTimeType.COUNTING_DOWN)
setCurrentShowTimeType(ShowTimeType.TIME);
}
}
@ -1354,6 +1416,9 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
handUPDialy--;
if(handUPDialy==0) {
switchMode(MODE_NORMAL);
if(!isArtificialHiddle&&showTimeType==ShowTimeType.TIME){
setCurrentShowTimeType(ShowTimeType.COUNTING);
}
}else
Player.getInstance().playHandUp(this);
return;
@ -1387,7 +1452,19 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
private void updateTime() {
heartbeat=!heartbeat;
DateModel date = new DateModel();
String timeString = model.isDisplaySecond() ? date.getTimeString(model.isHourSystem12()) : date.getShortTimeString(heartbeat,model.isHourSystem12());
String timeString=null;
switch (showTimeType){
case COUNTING:
DateModel temp=new DateModel(countingDateTimeBase);
timeString=temp.getTimeString(false);
break;
case COUNTING_DOWN:
timeString=DateModel.getTimeFull(handUpTime);
break;
default:
timeString = model.isDisplaySecond() ? date.getTimeString(model.isHourSystem12()) : date.getShortTimeString(heartbeat,model.isHourSystem12());
break;
}
setCurrentTimeToView(timeString);
reportTime(date);
updateDay(date);
@ -1607,6 +1684,9 @@ public class MainActivity extends Activity implements Handler.Callback, View.OnC
if(!isArtificialHiddle) {
tv_time.setLinearGradientRandom(!tv_time.isLinearGradientAble());
return true;
}else if(clockAnimator!=null){
clockAnimator.randPointer();
return true;
}
return false;
}

View File

@ -19,7 +19,14 @@ public class DateModel implements Serializable {
private int second = 0;
public DateModel() {
setDataString(getNowWithTime());
Calendar c1 = Calendar.getInstance(); //当前日期
year=c1.get(Calendar.YEAR);
month=c1.get(Calendar.MONTH)+1;
day=c1.get(Calendar.DAY_OF_MONTH);
hour=c1.get(Calendar.HOUR_OF_DAY);
minute=c1.get(Calendar.MINUTE);
second=c1.get(Calendar.SECOND);
//setDataString(getNowWithTime());
}
public DateModel(int year, int month, int day) {
@ -28,6 +35,15 @@ public class DateModel implements Serializable {
this.day = day;
}
public DateModel(Date base) {
Date date=new Date();
int between = new Long(date.getTime() - base.getTime()).intValue();
day = between / (24 * 60 * 60 * 1000);
hour = (between / (60 * 60 * 1000) - day * 24);
minute = ((between / (60 * 1000)) - day * 24 * 60 - hour * 60);
second = (between / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60);
}
/**
* @param timeString 12:00 || 12:00:00
*/
@ -144,6 +160,14 @@ public class DateModel implements Serializable {
return String.format("%02d:%02d:%02d", hours, minutes, second);
}
public static String getTimeFull(int second){
long hours = second / 3600;//转换小时数
second = second % 3600;//剩余秒数
long minutes = second / 60;//转换分钟
second = second % 60;//剩余秒数
return String.format("%02d:%02d:%02d", hours, minutes, second);
}
public int minusTime(DateModel strEnd) {
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
Date d1 = null;
@ -155,7 +179,6 @@ public class DateModel implements Serializable {
e.printStackTrace();
}
return (int) ((d2.getTime() - d1.getTime()) / DateUtils.SECOND_IN_MILLIS);
}

View File

@ -3,6 +3,13 @@ package clock.socoolby.com.clock.widget.animatorview.animator;
import clock.socoolby.com.clock.widget.animatorview.AbstractAnimator;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.AbstractClock;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.DefaultPointer;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.LeafPointer;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.LeafTwoPointer;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.SecondTailPointer;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.SwordPointer;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.TrianglePointer;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.TwoStepPointer;
// 参考自:https://github.com/ifadai/ClockDemo
public class ClockAnimator extends AbstractAnimator<AbstractClock> {
@ -35,4 +42,35 @@ public class ClockAnimator extends AbstractAnimator<AbstractClock> {
clock.init(width,height,width/2,height/2,minHigh/2,color,textColor);
list.add(clock);
}
int randPointerIndex=1;
public void randPointer(){
if(clock==null)
return;
if(randPointerIndex>6)
randPointerIndex=0;
switch (randPointerIndex){
case 1:
clock.setPointer(new SecondTailPointer());
break;
case 2:
clock.setPointer(new TrianglePointer());
break;
case 3:
clock.setPointer(new SwordPointer());
break;
case 4:
clock.setPointer(new TwoStepPointer());
break;
case 5:
clock.setPointer(new LeafPointer());
break;
case 6:
clock.setPointer(new LeafTwoPointer());
break;
default:
clock.setPointer(new DefaultPointer());
}
randPointerIndex++;
}
}

View File

@ -0,0 +1,156 @@
package clock.socoolby.com.clock.widget.animatorview.animator;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
import clock.socoolby.com.clock.widget.animatorview.AbstractCacheDifferenceAnimator;
import clock.socoolby.com.clock.widget.animatorview.I_AnimatorEntry;
//引用自:https://github.com/zhangyuChen1991/MagicLine
public class MagicLineAnimator extends AbstractCacheDifferenceAnimator<MagicLineAnimator.MagicLine, MagicLineAnimator.CorrdinateData> {
public MagicLineAnimator() {
super(1);
}
@Override
public MagicLine createNewEntry() {
return new MagicLine(width,height);
}
public static float[][] demos={{400,400,0.05f,200,200,0.35f},
{450,450,0.5f,450,450,0.15f},
{450,450,1.0f,150,150,0.15f},
{320,320,0.025f,320,80,0.06f},
{450,450,1.0f,150,150,0.15f},
{90, 90,0.5f, 450, 450, 0.15f},
{200, 200, 0.55f, 450, 450, 0.15f},
{450, 150, 0.15f, 150, 450, 0.05f},
{200, 500, 0.4f, 500, 200, 0.4f}
};
public class MagicLine implements I_AnimatorEntry {
//起点在xy移动范围
private float p1XLength = 400, p1YLength = 20, speedP1 = 0.15f;
private float p2XLength = 20, p2YLength = 400, speedP2 = 0.05f;
private double angleP1 = 0, angleP2 = 0;
private int viewWidth, viewHeight;
private Paint paint;
//记录移动过的所有点的数据
private List<CorrdinateData> corrDatas;
//动画绘制的时间
private int animDuration = 600;
public MagicLine(int viewWidth, int viewHeight) {
this.viewWidth = viewWidth;
this.viewHeight = viewHeight;
init();
}
@Override
public void move(int maxWidth, int maxHight) {
calculate();
animDuration--;
if(animDuration==0) {
animDuration = 600;
reStartDraw();
}
}
@Override
public void onDraw(Canvas canvas, Paint mPaint) {
for (int i = 0; i < corrDatas.size(); i++) {
CorrdinateData cd = corrDatas.get(i);
paint.setColor(cd.color);
canvas.drawLine(cd.p1X, cd.p1Y, cd.p2X, cd.p2Y, paint);
}
}
private void init() {
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
//paint.setColor(Color.WHITE);
paint.setAlpha(50);
// Shader shader = new LinearGradient(cd.p1X, cd.p1Y, cd.p2X, cd.p2Y, colors, null, Shader.TileMode.MIRROR);
// paint.setShader(shader);
corrDatas = new ArrayList<>();
}
/**
* 开始绘制
*/
public void reStartDraw() {
moveToTrashCache(corrDatas);
corrDatas.clear();
int demoIndex=rand.nextInt(demos.length);
p1XLength = demos[demoIndex][0];
p1YLength = demos[demoIndex][1];
speedP1 = demos[demoIndex][2];
p2XLength = demos[demoIndex][3];
p2YLength = demos[demoIndex][4];
speedP2 = demos[demoIndex][5];
}
/**
* 计算坐标值
*/
private void calculate() {
angleP1 = angleP1 + speedP1;
angleP2 = angleP2 + speedP2;
//两个点的位置更新
float nowP1X = (float) (p1XLength * Math.cos(angleP1) + viewWidth / 2f);
float nowP1Y = (float) (p1YLength * Math.sin(angleP1) + viewHeight / 2f);
float nowP2X = (float) (p2XLength * Math.cos(angleP2) + viewWidth / 2f);
float nowP2Y = (float) (p2YLength * Math.sin(angleP2) + viewHeight / 2f);
CorrdinateData corrdinataData =revectForTrashCache();
randomColorIfAble();
if(corrdinataData!=null)
corrdinataData.init(nowP1X, nowP1Y, nowP2X, nowP2Y,color);
else
corrdinataData=new CorrdinateData(nowP1X, nowP1Y, nowP2X, nowP2Y,color);
corrDatas.add(corrdinataData);
}
/**
* 设置参数
*/
public void setParam(float p1XLength, float p1YLength, float p2XLength, float p2YLength, float speedP1, float speedP2) {
this.p1XLength = p1XLength;
this.p1YLength = p1YLength;
this.p2XLength = p2XLength;
this.p2YLength = p2YLength;
this.speedP1 = speedP1;
this.speedP2 = speedP2;
}
}
public class CorrdinateData {
float p1X, p1Y, p2X, p2Y;
int color;
CorrdinateData(float p1X, float p1Y, float p2X, float p2Y,int color) {
init(p1X,p1Y,p2X,p2Y,color);
}
public void init(float p1X, float p1Y, float p2X, float p2Y,int color) {
this.p1X = p1X;
this.p1Y = p1Y;
this.p2X = p2X;
this.p2Y = p2Y;
this.color=color;
}
}
}

View File

@ -0,0 +1,314 @@
package clock.socoolby.com.clock.widget.animatorview.animator;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import clock.socoolby.com.clock.widget.animatorview.AbstractAnimator;
import clock.socoolby.com.clock.widget.animatorview.I_AnimatorEntry;
//参考自:http://refactor.cn/2016/12/26/GearMachine-Canvas绘制漂亮的齿轮装置/
public class SawtoothAnimator extends AbstractAnimator<SawtoothAnimator.Sawtooth> {
public SawtoothAnimator() {
super(1);
}
@Override
public Sawtooth createNewEntry() {
return new Sawtooth(width,height);
}
@Override
public int dialyTime() {
return 20;
}
public class Sawtooth implements I_AnimatorEntry {
private static final int X = 0;
private static final int Y = 1;
private float mTopCircleRadius;
private float mBottomBigCircleRadius;
private Paint mRedPaint, mDarkRedPaint, mStrokePaint, mBeltPaint;
private Paint mTransitionPaint, mTransitionDarkPaint;
private Path mBigSawtoothPath, mSmallSawtoothPath;
private Path mLeftTopTrianglePath, mRightTopTrianglePath, mBarPath, mSmallBarPath;
private float mCurProgress;
private RectF mShadeRectF;
private PorterDuffXfermode mClearXfermode;
private int width,hight;
public Sawtooth(int width, int hight) {
this.width = width;
this.hight = hight;
init();
mCurProgress=0f;
}
/**
* 确定四个点
* 1. 左上齿轮中心 宽占完整宽度的比例0.237 高占完整宽度的比例 0.102
* 2. 右上齿轮中心 宽占完整宽度的比例0.763 高占完整宽度的比例 0.102
* 3. 中上齿轮中心 宽占完整宽度的比例0.5 高占完整宽度的比例 0.311
* 4. 中下齿轮中心 宽占完整宽度的比例0.5 高占完整宽度的比例 0.597
*/
private float[] mLeftTopCentre, mRightTopCentre, mTopCentre, mBottomCentre;
private void init() {
mLeftTopCentre = new float[2];
mRightTopCentre = new float[2];
mTopCentre = new float[2];
mBottomCentre = new float[2];
mRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRedPaint.setStrokeJoin(Paint.Join.ROUND);
mRedPaint.setStrokeCap(Paint.Cap.ROUND);
mRedPaint.setColor(Color.RED);
mDarkRedPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mDarkRedPaint.setStrokeJoin(Paint.Join.ROUND);
mDarkRedPaint.setStrokeCap(Paint.Cap.ROUND);
mDarkRedPaint.setStyle(Paint.Style.FILL);
mDarkRedPaint.setColor(color);
mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mStrokePaint.setStrokeJoin(Paint.Join.ROUND);
mStrokePaint.setStrokeCap(Paint.Cap.ROUND);
mStrokePaint.setStyle(Paint.Style.STROKE);
mStrokePaint.setColor(Color.RED);
mTransitionPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTransitionPaint.setStrokeJoin(Paint.Join.ROUND);
mTransitionPaint.setStrokeCap(Paint.Cap.ROUND);
mTransitionPaint.setStyle(Paint.Style.FILL);
mTransitionPaint.setColor(color);
mTransitionDarkPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTransitionDarkPaint.setStrokeJoin(Paint.Join.ROUND);
mTransitionDarkPaint.setStrokeCap(Paint.Cap.ROUND);
mTransitionDarkPaint.setStyle(Paint.Style.FILL);
mTransitionDarkPaint.setColor(Color.DKGRAY);
mBeltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBeltPaint.setStrokeJoin(Paint.Join.ROUND);
mBeltPaint.setStrokeCap(Paint.Cap.ROUND);
mBeltPaint.setStyle(Paint.Style.FILL);
mBeltPaint.setColor(Color.RED);
mClearXfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
int paddingLeft = 0;
int paddingRight = 0;
int paddingTop = 0;
int paddingBottom = 0;
// 横向有效宽度
int validWidth = width - paddingLeft - paddingRight;
// 纵向有效高度
int validHeight = height - paddingTop - paddingBottom;
// 左上齿轮中心
mLeftTopCentre[X] = (float) (paddingLeft + validWidth * 0.237);
mLeftTopCentre[Y] = (float) (paddingTop + validHeight * 0.102);
// 右上齿轮中心
mRightTopCentre[X] = (float) (paddingLeft + validWidth * 0.763);
mRightTopCentre[Y] = (float) (paddingTop + validHeight * 0.102);
// 中上齿轮中心
mTopCentre[X] = (float) (paddingLeft + validWidth * 0.5);
mTopCentre[Y] = (float) (paddingTop + validHeight * 0.311);
// 中下齿轮中心
mBottomCentre[X] = (float) (paddingLeft + validWidth * 0.5);
mBottomCentre[Y] = (float) (paddingTop + validHeight * 0.597);
// 上部两个齿轮的半径
mTopCircleRadius = (float) (validWidth * 0.102);
// 最大的齿轮stroke size
mBottomBigCircleRadius = validWidth / 2 - mTopCircleRadius / 4 * 5;
mStrokePaint.setStrokeWidth(mTopCircleRadius / 4 * 5);
// 传送带stroke size
mBeltPaint.setStrokeWidth((float) (validWidth * 0.0077));
// 大齿轮Path
mBigSawtoothPath = new Path();
mBigSawtoothPath.moveTo((float) (mBottomCentre[X] - validWidth * 0.03), (float) (mBottomCentre[Y] - mBottomBigCircleRadius - mStrokePaint.getStrokeWidth() / 2 * 0.9)); // 此处的0.9表示未被绘制上的偏移量
mBigSawtoothPath.lineTo((float) (mBottomCentre[X] - validWidth * 0.025), (float) (mBottomCentre[Y] - (mBottomBigCircleRadius + mStrokePaint.getStrokeWidth() / 3 * 2.4))); // 此处的mStrokePaint.getStrokeWidth() / 3 * 2.4 代表最大锯齿的高度
mBigSawtoothPath.lineTo((float) (mBottomCentre[X] + validWidth * 0.025), (float) (mBottomCentre[Y] - (mBottomBigCircleRadius + mStrokePaint.getStrokeWidth() / 3 * 2.4)));
mBigSawtoothPath.lineTo((float) (mBottomCentre[X] + validWidth * 0.03), (float) (mBottomCentre[Y] - mBottomBigCircleRadius - mStrokePaint.getStrokeWidth() / 2 * 0.9));
mBigSawtoothPath.close();
mBigSawtoothPath.close();
// 小齿轮Path
mSmallSawtoothPath = new Path();
mSmallSawtoothPath.moveTo((float) (mBottomCentre[X] - validWidth * 0.01), (float) (mBottomCentre[Y] - (mTopCircleRadius / 2 * 2.8))); // 此处的12 代表梯形底边的一半
mSmallSawtoothPath.lineTo((float) (mBottomCentre[X] - validWidth * 0.013), (float) (mBottomCentre[Y] - (mTopCircleRadius / 2 * 3.2))); // 此处的10 代表梯形顶边的一半
mSmallSawtoothPath.lineTo((float) (mBottomCentre[X] + validWidth * 0.013), (float) (mBottomCentre[Y] - (mTopCircleRadius / 2 * 3.2))); // 此处的10 代表梯形顶边的一半
mSmallSawtoothPath.lineTo((float) (mBottomCentre[X] + validWidth * 0.01), (float) (mBottomCentre[Y] - (mTopCircleRadius / 2 * 2.8)));
mSmallSawtoothPath.close();
// 左上角三角齿轮
mLeftTopTrianglePath = new Path();
mLeftTopTrianglePath.moveTo((float) (mLeftTopCentre[X] - validWidth * 0.0082), mLeftTopCentre[Y] - (mTopCircleRadius / 4 * 2));
mLeftTopTrianglePath.lineTo(mLeftTopCentre[X] , (float) (mLeftTopCentre[Y] - (mTopCircleRadius / 4 * 2.6))); // 此处的10 是三角形底边的一半
mLeftTopTrianglePath.lineTo((float) (mLeftTopCentre[X] + validWidth * 0.0082), mLeftTopCentre[Y] - (mTopCircleRadius / 4 * 2));
mLeftTopTrianglePath.close();
// 右上角三角齿轮
mRightTopTrianglePath = new Path();
mRightTopTrianglePath.moveTo((float) (mRightTopCentre[X] - validWidth * 0.0082), mRightTopCentre[Y] - (mTopCircleRadius / 4 * 2));
mRightTopTrianglePath.lineTo(mRightTopCentre[X] , (float) (mRightTopCentre[Y] - (mTopCircleRadius / 4 * 2.6))); // 此处的10 是三角形底边的一半
mRightTopTrianglePath.lineTo((float) (mRightTopCentre[X] + validWidth * 0.0082), mRightTopCentre[Y] - (mTopCircleRadius / 4 * 2));
mRightTopTrianglePath.close();
// 上方斜杆
mBarPath = new Path();
mBarPath.moveTo(mTopCentre[X] - mTopCircleRadius, mTopCentre[Y]);
mBarPath.lineTo(mRightTopCentre[X] - mTopCircleRadius, mRightTopCentre[Y]);
mBarPath.lineTo(mRightTopCentre[X] + mTopCircleRadius, mRightTopCentre[Y]);
mBarPath.lineTo(mTopCentre[X] + mTopCircleRadius, mTopCentre[Y]);
mBarPath.close();
mSmallBarPath = new Path();
mSmallBarPath.moveTo((float) (mTopCentre[X] - mTopCircleRadius * 0.3), mTopCentre[Y]);
mSmallBarPath.lineTo((float) (mRightTopCentre[X] - mTopCircleRadius * 0.3), mRightTopCentre[Y]);
mSmallBarPath.lineTo((float) (mRightTopCentre[X] + mTopCircleRadius * 0.3), mRightTopCentre[Y]);
mSmallBarPath.lineTo((float) (mTopCentre[X] + mTopCircleRadius * 0.3), mTopCentre[Y]);
mSmallBarPath.close();
mShadeRectF = new RectF(0, mBottomCentre[Y] - width / 2, width, mBottomCentre[Y] + width / 2);
}
@Override
public void onDraw(Canvas canvas, Paint mPaint) {
// 中下最大的齿轮
canvas.drawCircle(mBottomCentre[X], mBottomCentre[Y], mBottomBigCircleRadius, mStrokePaint);
canvas.save();
canvas.rotate(mCurProgress * 180, mBottomCentre[X], mBottomCentre[Y]);
for (int i = 0; i < 18; i ++) {
// 中心齿轮最外围的齿轮上的锯齿 梯形
canvas.drawPath(mBigSawtoothPath, mRedPaint);
canvas.rotate(20.0f, mBottomCentre[X], mBottomCentre[Y]);
}
canvas.restore();
// 大齿轮扇形遮罩
mDarkRedPaint.setXfermode(mClearXfermode);
canvas.drawArc(mShadeRectF, 180, 130, true, mDarkRedPaint);
mDarkRedPaint.setXfermode(null);
// 上方两个齿轮底下的斜向连杆
canvas.drawPath(mBarPath, mTransitionPaint);
canvas.drawPath(mSmallBarPath, mTransitionDarkPaint);
// 上方两个齿轮底下的横向连杆
canvas.drawRect(mLeftTopCentre[X], mLeftTopCentre[Y] - mTopCircleRadius / 4 * 3, mRightTopCentre[X], mRightTopCentre[Y] + mTopCircleRadius / 4 * 3, mRedPaint);
// 左上齿轮
canvas.drawCircle(mLeftTopCentre[X], mLeftTopCentre[Y], mTopCircleRadius, mRedPaint);
canvas.drawCircle(mLeftTopCentre[X], mLeftTopCentre[Y], mTopCircleRadius / 4 * 3, mDarkRedPaint);
canvas.save();
canvas.rotate(mCurProgress * 360, mLeftTopCentre[X], mLeftTopCentre[Y]);
for (int i = 0; i < 24; i ++) {
// 齿轮的三角 path
canvas.drawPath(mLeftTopTrianglePath, mRedPaint);
canvas.rotate(15.0f, mLeftTopCentre[X], mLeftTopCentre[Y]);
}
canvas.restore();
canvas.drawCircle(mLeftTopCentre[X], mLeftTopCentre[Y], mTopCircleRadius / 2, mRedPaint);
canvas.drawCircle(mLeftTopCentre[X], mLeftTopCentre[Y], mTopCircleRadius / 5 * 2, mDarkRedPaint);
canvas.drawCircle(mLeftTopCentre[X], mLeftTopCentre[Y], mTopCircleRadius / 4, mRedPaint);
// 右上齿轮
canvas.drawCircle(mRightTopCentre[X], mRightTopCentre[Y], mTopCircleRadius, mRedPaint);
canvas.drawCircle(mRightTopCentre[X], mRightTopCentre[Y], mTopCircleRadius / 4 * 3, mDarkRedPaint);
canvas.save();
canvas.rotate(-mCurProgress * 360, mRightTopCentre[X], mRightTopCentre[Y]);
for (int i = 0; i < 24; i ++) {
// 齿轮的三角 path
canvas.drawPath(mRightTopTrianglePath, mRedPaint);
canvas.rotate(15.0f, mRightTopCentre[X], mRightTopCentre[Y]);
}
canvas.restore();
canvas.drawCircle(mRightTopCentre[X], mRightTopCentre[Y], mTopCircleRadius / 2, mRedPaint);
canvas.drawCircle(mRightTopCentre[X], mRightTopCentre[Y], mTopCircleRadius / 5 * 2, mDarkRedPaint);
canvas.drawCircle(mRightTopCentre[X], mRightTopCentre[Y], mTopCircleRadius / 4, mRedPaint);
// 中上齿轮
canvas.drawCircle(mTopCentre[X], mTopCentre[Y], mTopCircleRadius, mRedPaint);
canvas.drawCircle(mTopCentre[X], mTopCentre[Y], mTopCircleRadius / 4 * 3, mDarkRedPaint);
canvas.drawCircle(mTopCentre[X], mTopCentre[Y], mTopCircleRadius / 4, mRedPaint);
canvas.save();
canvas.rotate(mCurProgress * 225, mTopCentre[X], mTopCentre[Y]);
for (int i = 0; i < 8; i ++) {
// 圆盘上的小圆点
canvas.drawCircle(mTopCentre[X], mTopCentre[Y] - (mTopCircleRadius / 4 * 2), (float) (mTopCircleRadius * 0.0625), mRedPaint); // 此处的(mTopCircleRadius * 0.125) 表示小圆球的半径
canvas.rotate(45.0f, mTopCentre[X], mTopCentre[Y]);
}
canvas.restore();
// 中下齿轮
canvas.save();
canvas.rotate(-mCurProgress * 216, mBottomCentre[X], mBottomCentre[Y]);
for (int i = 0; i < 15; i ++) {
// 中心齿轮最外围的齿轮上的锯齿 梯形
canvas.drawPath(mSmallSawtoothPath, mDarkRedPaint);
canvas.rotate(24.0f, mBottomCentre[X], mBottomCentre[Y]);
}
canvas.restore();
canvas.drawCircle(mBottomCentre[X], mBottomCentre[Y], mTopCircleRadius / 2 * 3, mDarkRedPaint);
canvas.drawCircle(mBottomCentre[X], mBottomCentre[Y], mTopCircleRadius / 16 * 17, mRedPaint);
// 投影
mRedPaint.setShadowLayer(10.0f, 0f, 6.0f, Color.LTGRAY);
canvas.drawCircle(mBottomCentre[X], mBottomCentre[Y], mTopCircleRadius / 80 * 55, mRedPaint);
mRedPaint.setShadowLayer(0f, 0f, 0f, Color.LTGRAY);
canvas.drawCircle(mBottomCentre[X], mBottomCentre[Y], mTopCircleRadius / 80 * 40, mDarkRedPaint);
canvas.save();
canvas.rotate(mCurProgress * 180, mBottomCentre[X], mBottomCentre[Y]);
for (int i = 0; i < 8; i ++) {
// 圆盘上的小圆点
canvas.drawCircle(mBottomCentre[X], (float) (mBottomCentre[Y] - (mTopCircleRadius / 4 * 1.2)), (float) (mTopCircleRadius * 0.05), mRedPaint);
canvas.rotate(45.0f, mBottomCentre[X], mBottomCentre[Y]);
}
canvas.restore();
canvas.drawCircle(mBottomCentre[X], mBottomCentre[Y], mTopCircleRadius / 8, mRedPaint);
// 左侧传送带
canvas.drawLine(mTopCentre[X] - mTopCircleRadius * 0.85f, mTopCentre[Y],
mBottomCentre[X] - mTopCircleRadius * 0.6f, mBottomCentre[Y],
mBeltPaint);
// 右侧传送带
canvas.drawLine(mTopCentre[X] + mTopCircleRadius * 0.85f, mTopCentre[Y],
mBottomCentre[X] + mTopCircleRadius * 0.6f, mBottomCentre[Y],
mBeltPaint);
}
@Override
public void move(int maxWidth, int maxHight) {
mCurProgress +=0.1f;
if(mCurProgress>1)
mCurProgress=0;
}
}
}

View File

@ -2,16 +2,10 @@ package clock.socoolby.com.clock.widget.animatorview.animator;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.DrawFilter;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.Shader;
import java.util.ArrayList;
import java.util.List;
import static java.lang.Float.parseFloat;
import clock.socoolby.com.clock.widget.animatorview.AbstractAnimator;
import clock.socoolby.com.clock.widget.animatorview.I_AnimatorEntry;
@ -30,254 +24,93 @@ public class WaterAnimator extends AbstractAnimator<WaterAnimator.Water> {
@Override
public Water createNewEntry() {
int startColor=Color.parseColor("#00FFFFFF");
int waveColor=color;
randomColorIfAble();
return new Water(width,height,waveColor,startColor,color);
//randomColorIfAble();
return new Water(0,0,width,height,height*3/4);
}
class Water implements I_AnimatorEntry {
private Path mAbovePath, mBelowWavePath;
private Paint mAboveWavePaint, mBelowWavePaint;
private Paint mPaint = new Paint();
private Matrix mMatrix = new Matrix();
private List<Wave> mltWave = new ArrayList<>();
private int mWaveHeight;
private int mStartColor;
private int mCloseColor;
private int mGradientAngle;
private float mVelocity;
private float mColorAlpha;
private float mProgress;
private long mLastTime = 0;
private String tag;
private DrawFilter mDrawFilter;
public Water(int w,int h,int color,int mStartColor,int mCloseColor) {
mPaint.setAntiAlias(true);
mPaint.setColor(color);
mWaveHeight = Util.dipToPX(context,50);
this.mStartColor = mStartColor;
this.mCloseColor = mCloseColor;
mColorAlpha = 0.45f;
mProgress = 1f;
mVelocity = 1f;
mGradientAngle = 45;
tag="70,25,1.4,1.4,-26\n" +
"100,5,1.4,1.2,15\n" +
"420,0,1.15,1,-10\n" +
"520,10,1.7,1.5,20\n" +
"220,0,1,1,-15";
private float φ;
private double ω;
private float y, y2;
updateWavePath(w, h);
updateLinearGradient(w, h);
private int width,higth,left,top;
public Water(int left,int top,int width, int higth,int y2) {
this.width = width;
this.higth = higth;
this.left=left;
this.top=top;
this.y2=y2;
init();
}
public void runWave() {
protected void init() {
//初始化路径
mAbovePath = new Path();
mBelowWavePath = new Path();
//初始化画笔
//上方波浪
mAboveWavePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mAboveWavePaint.setAntiAlias(true);
mAboveWavePaint.setStyle(Paint.Style.FILL);
mAboveWavePaint.setColor(Color.BLUE);
//下方波浪
mBelowWavePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBelowWavePaint.setAntiAlias(true);
mBelowWavePaint.setStyle(Paint.Style.FILL);
mBelowWavePaint.setColor(Color.BLUE);
mBelowWavePaint.setAlpha(60);
//画布抗锯齿
mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
}
private void updateLinearGradient(int width, int height) {
//int startColor = Util.getColorWithAlpha(mStartColor, mColorAlpha*255);
//int closeColor = Util.getColorWithAlpha(mCloseColor, mColorAlpha*255);
//noinspection UnnecessaryLocalVariable
//double w = width;
//double h = height * mProgress;
//double r = Math.sqrt(w * w + h * h) / 2;
//double y = r * Math.sin(2 * Math.PI * mGradientAngle / 360);
//double x = r * Math.cos(2 * Math.PI * mGradientAngle / 360);
//mPaint.setShader(new LinearGradient((int)(w/2-x), (int)(h/2-y), (int)(w/2+x), (int)(h/2+y), startColor, closeColor, Shader.TileMode.CLAMP));
}
private void updateWavePath(int w, int h) {
mltWave.clear();
if (tag instanceof String) {
String[] waves = tag.toString().split("\\s+");
if ("-1".equals(tag)) {
waves = "70,25,1.4,1.4,-26\n100,5,1.4,1.2,15\n420,0,1.15,1,-10\n520,10,1.7,1.5,20\n220,0,1,1,-15".split("\\s+");
} else if ("-2".equals(tag)) {
waves = "0,0,1,0.5,90\n90,0,1,0.5,90".split("\\s+");
}
for (String wave : waves) {
String[] args = wave.split ("\\s*,\\s*");
if (args.length == 5) {
mltWave.add(new Wave(Util.dipToPX(context,parseFloat(args[0])), Util.dipToPX(context,parseFloat(args[1])), Util.dipToPX(context,parseFloat(args[4])), parseFloat(args[2]), parseFloat(args[3]), w, h, mWaveHeight/2));
}
}
} else {
mltWave.add(new Wave(Util.dipToPX(context,50), Util.dipToPX(context,0), Util.dipToPX(context,5), 1.7f, 2f, w, h, mWaveHeight/2));
}
}
@Override
public void move(int maxWidth, int maxHight) {
runWave();
φ -= 0.1f;
ω = 2 * Math.PI / width;
}
@Override
public void onDraw(Canvas canvas, Paint paint) {
if (mltWave.size() > 0 && mPaint != null) {
long thisTime = System.currentTimeMillis();
for (Wave wave : mltWave) {
mMatrix.reset();
canvas.save();
if (mLastTime > 0 && wave.velocity != 0) {
float offsetX = (wave.offsetX - (wave.velocity * mVelocity * (thisTime - mLastTime) / 1000f));
if (-wave.velocity > 0) {
offsetX %= wave.width / 2;
} else {
while (offsetX < 0) {
offsetX += (wave.width / 2);
}
}
wave.offsetX = offsetX;
mMatrix.setTranslate(offsetX, (1 - mProgress) * height);
canvas.translate(-offsetX, -wave.offsetY - (1 - mProgress) * height);
} else{
mMatrix.setTranslate(wave.offsetX, (1 - mProgress) * height);
canvas.translate(-wave.offsetX, -wave.offsetY - (1 - mProgress) * height);
}
//mPaint.getShader().setLocalMatrix(mMatrix);
canvas.drawPath(wave.path, mPaint);
canvas.restore();
public void onDraw(Canvas canvas, Paint mPaint) {
canvas.setDrawFilter(mDrawFilter);
mAbovePath.reset();
mBelowWavePath.reset();
mAbovePath.moveTo(left, higth);
// mBelowWavePath.moveTo(getLeft(), getBottom() + 15);
for (float x = 0; x <= width; x++) {
/**
* y=Asin(ωx+φ)+k
* A振幅越大波形在y轴上最大与最小值的差值越大
* ω角速度 控制正弦周期(单位角度内震动的次数)
* φ初相反映在坐标系上则为图像的左右移动这里通过不断改变φ,达到波浪移动效果
* k偏距反映在坐标系上则为图像的上移或下移
*/
y = (float) (30 * Math.cos(ω * x + φ) + 30)+y2;
// y2 = (float) (30 * Math.sin(ω * x + φ) + 30);
mAbovePath.lineTo(x, y);
// mBelowWavePath.lineTo(x, y2);
if (x == width / 2) {
mPaint.setColor(color);
canvas.drawCircle(x, y-40, 20, mPaint);
//mWaveAnimationListener.OnWaveAnimation(y);
}
mLastTime = thisTime;
}
}
}
/**
* 水波对象
* Created by SCWANG on 2017/12/11.
*/
class Wave {
Path path; //水波路径
int width; //画布宽度2倍波长
int wave; //波幅振幅
float offsetX; //水波的水平偏移量
float offsetY; //水波的竖直偏移量
float velocity; //水波移动速度像素/
private float scaleX; //水平拉伸比例
private float scaleY; //竖直拉伸比例
/**
* 通过参数构造一个水波对象
*
* @param offsetX 水平偏移量
* @param offsetY 竖直偏移量
* @param velocity 移动速度像素/
* @param scaleX 水平拉伸量
* @param scaleY 竖直拉伸量
* @param w 波长
* @param h 画布高度
* @param wave 波幅波宽度
*/
public Wave(int offsetX, int offsetY, int velocity, float scaleX, float scaleY, int w, int h, int wave) {
this.width = (int) (2 * scaleX * w); //画布宽度2倍波长
this.wave = wave; //波幅波宽
this.scaleX = scaleX; //水平拉伸量
this.scaleY = scaleY; //竖直拉伸量
this.offsetX = offsetX; //水平偏移量
this.offsetY = offsetY; //竖直偏移量
this.velocity = velocity; //移动速度像素/
this.path = buildWavePath(width, h);
}
/*
* 根据 波长度中轴线高度波幅 绘制水波路径
*/
public void updateWavePath(int w, int h, int waveHeight) {
this.wave = (wave > 0) ? wave : waveHeight / 2;
this.width = (int) (2 * scaleX * w); //画布宽度2倍波长
this.path = buildWavePath(width, h);
}
private Path buildWavePath(int width, int height) {
int DP = Util.dipToPX(context, 1);//一个dp在当前设备表示的像素量水波的绘制精度设为一个dp单位
if (DP < 1) {
DP = 1;
}
int wave = (int) (scaleY * this.wave);//计算拉伸之后的波幅
Path path = new Path();
//path.moveTo(0, 0);
//path.lineTo(0, height - wave);
path.moveTo(0, height);
path.lineTo(0, height - wave);
for (int x = DP; x < width; x += DP) {
path.lineTo(x, height - wave - wave * (float) Math.sin(4.0 * Math.PI * x / width));
}
path.lineTo(width, height - wave);
//path.lineTo(width, 0);
path.lineTo(width, height);
path.close();
return path;
}
}
/**
* 绘制外层的刻度
*
* @param canvas
protected void drawOutArc(Canvas canvas) {
canvas.save();
for (int i = 0; i < 100; i++) {
if (i < mPercent) {
mOutProgressPaint.setColor(mProgressColor);
} else {
mOutProgressPaint.setColor(mOutBaseColor);
}
canvas.rotate(3.6f, width / 2, height / 2);
canvas.drawLine(width / 2, 0, height / 2, mDefaultLineLen, mOutProgressPaint);
}
canvas.restore();
}
*/
/**
* 根据 最高点获取贝塞尔曲线的 控制点
*
* @param startPointF 开始点
* @param endPointF 结束点
* @param bezierPointF 最高点
* @return 控制点
*/
public static Point getControlPointF(Point startPointF, Point endPointF, Point bezierPointF) {
//B(t)=(1-t)^2P0+2t(1-t)P1+t^2P2;
Point controlPointF = new Point(0l, 0l);
float tmp = 0.5F;
float t = 0.5F;
controlPointF.setX((bezierPointF.x - tmp * tmp * startPointF.y - t * t * endPointF.y) / (2 * t * tmp));
controlPointF.setY((bezierPointF.y- tmp * tmp * startPointF.y - t * t * endPointF.y) / (2 * t * tmp));
return controlPointF;
}
public static class Point{
public float x,y;
public Point(float x,float y){
this.x=x;
this.y=y;
}
public void setX(float x){
this.x=x;
}
public void setY(float y){
this.y=y;
//回调 把y坐标的值传出去(在activity里面接收让小机器人随波浪一起摇摆)
mAbovePath.lineTo(width, higth);
// mBelowWavePath.lineTo(getRight(), getBottom() + 15);
canvas.drawPath(mAbovePath, mAboveWavePaint);
// canvas.drawPath(mBelowWavePath, mBelowWavePaint);
}
}

View File

@ -6,32 +6,31 @@ import android.graphics.Paint;
import java.util.Calendar;
import clock.socoolby.com.clock.widget.animatorview.I_AnimatorEntry;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer.DefaultPointer;
public abstract class AbstractClock implements I_AnimatorEntry {
protected int width,hight;
protected int mCenterX, mCenterY;
// 默认刻度画笔指针画笔文字画笔
protected Paint mDefaultPaint, mPointerPaint, mTextPaint;
// 默认刻度画笔文字画笔
protected Paint mDefaultPaint, mTextPaint;
// 时钟半径中心点半径默认刻度长度默认刻度宽度特殊刻度长度特殊刻度宽度
// 时指针长度时钟指针宽度分钟指针长度分钟指针宽度秒钟指针长度秒钟指针宽度
protected float mRadius, mPointRadius,
// 时钟半径中心点半径默认刻度长度默认刻度宽度特殊刻度长度特殊刻度宽度
protected float mRadius,
mDefaultScaleLength, mDefaultScaleWidth,
mParticularlyScaleLength, mParticularlyScaleWidth,
mHourPointerLength, mHourPointerWidth,
mMinutePointerLength, mMinutePointerWidth,
mSecondPointerLength, mSecondPointerWidth;
mParticularlyScaleLength, mParticularlyScaleWidth;
// 当前时
protected int mH, mM, mS;
// 时钟颜色默认刻度颜色时刻度颜色时针颜色分针颜色秒针颜色
protected int mClockColor, mColorDefaultScale, mColorParticularyScale, mColorHourPointer,
mColorMinutePointer, mColorSecondPointer,textColor;
// 时钟颜色默认刻度颜色时刻度颜色
protected int mClockColor, mColorDefaultScale, mColorParticularyScale,textColor;
I_Pointer pointer;
public AbstractClock() {
}
public void init(int width,int hight,int mCenterX, int mCenterY, float mRadius, int mClockColor,int textColor){
@ -42,35 +41,51 @@ public abstract class AbstractClock implements I_AnimatorEntry {
this.mRadius = mRadius;
this.mClockColor = mClockColor;
this.textColor=textColor;
initScaleLength();
init();
setPointer(new DefaultPointer());
}
private void init() {
mColorDefaultScale = mClockColor;
mColorParticularyScale = mClockColor;
mColorHourPointer = mClockColor;
mColorMinutePointer = mClockColor;
mColorSecondPointer = mClockColor;
mDefaultPaint = new Paint();
mDefaultPaint.setAntiAlias(true);
mDefaultPaint.setStyle(Paint.Style.STROKE);
mPointerPaint = new Paint();
mPointerPaint.setAntiAlias(true);
mPointerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPointerPaint.setTextSize(14);
mPointerPaint.setStrokeCap(Paint.Cap.ROUND);
mTextPaint = new Paint();
mPointerPaint.setAntiAlias(true);
mPointerPaint.setStyle(Paint.Style.FILL);
mPointerPaint.setColor(mClockColor);
initClockPointerLength();
mTextPaint.setStrokeWidth(mDefaultScaleWidth / 2);
mTextPaint.setTextSize(mParticularlyScaleWidth * 4);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setColor(textColor);
}
protected void initScaleLength(){
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
mDefaultScaleLength = mRadius / 10;
mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
mParticularlyScaleLength = mRadius / 5;
mParticularlyScaleWidth = mParticularlyScaleLength / 6;
}
public void setPointer(I_Pointer pointer){
this.pointer=pointer;
pointer.init(mRadius,mClockColor);
}
/**
* 获取当前系统时间
*/
@ -95,21 +110,14 @@ public abstract class AbstractClock implements I_AnimatorEntry {
mS = s;
}
/**
* 根据控件的大小初始化时钟刻度的长度和宽度指针的长度和宽度时钟中心点的半径
*/
protected abstract void initClockPointerLength();
public void onDraw(Canvas canvas, Paint mPaint) {
setTextPaint();
drawBorder(canvas);
drawOrnament(canvas);
// 坐标原点移动到View 中心
canvas.translate(mCenterX, mCenterY);
drawText(canvas);
drawPointer(canvas);
pointer.drawPointer(canvas,mH,mM,mS,mPaint);
}
/**
@ -204,83 +212,6 @@ public abstract class AbstractClock implements I_AnimatorEntry {
canvas.drawText(h, y, 0 + offsetY, mTextPaint);
}
protected void setTextPaint() {
mTextPaint.setStrokeWidth(mDefaultScaleWidth / 2);
mTextPaint.setTextSize(mParticularlyScaleWidth * 4);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setColor(textColor);
}
/**
* 绘制指针
*/
protected void drawPointer(Canvas canvas) {
drawHourPointer(canvas);
drawMinutePointer(canvas);
drawSecondPointer(canvas);
mPointerPaint.setColor(mClockColor);
// 绘制中心原点需要在指针绘制完成后才能绘制
canvas.drawCircle(0, 0, mPointRadius, mPointerPaint);
}
/**
* 绘制时针
*/
protected void drawHourPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mHourPointerWidth);
mPointerPaint.setColor(mColorHourPointer);
// 当前时间的总秒数
float s = mH * 60 * 60 + mM * 60 + mS;
// 百分比
float percentage = s / (12 * 60 * 60);
// 通过角度计算弧度值因为时钟的角度起线是y轴负方向而View角度的起线是x轴正方向所以要加270度
float angle = 270 + 360 * percentage;
float x = (float) (mHourPointerLength * Math.cos(Math.PI * 2 / 360 * angle));
float y = (float) (mHourPointerLength * Math.sin(Math.PI * 2 / 360 * angle));
canvas.drawLine(0, 0, x, y, mPointerPaint);
}
/**
* 绘制分针
*/
protected void drawMinutePointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mMinutePointerWidth);
mPointerPaint.setColor(mColorMinutePointer);
float s = mM * 60 + mS;
float percentage = s / (60 * 60);
float angle = 270 + 360 * percentage;
float x = (float) (mMinutePointerLength * Math.cos(Math.PI * 2 / 360 * angle));
float y = (float) (mMinutePointerLength * Math.sin(Math.PI * 2 / 360 * angle));
canvas.drawLine(0, 0, x, y, mPointerPaint);
}
/**
* 绘制秒针
*/
protected void drawSecondPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mSecondPointerWidth);
mPointerPaint.setColor(mColorSecondPointer);
float s = mS;
float percentage = s / 60;
float angle = 270 + 360 * percentage;
float x = (float) (mSecondPointerLength * Math.cos(Math.PI * 2 / 360 * angle));
float y = (float) (mSecondPointerLength * Math.sin(Math.PI * 2 / 360 * angle));
canvas.drawLine(0, 0, x, y, mPointerPaint);
}
@Override
public void move(int maxWidth, int maxHight) {
getTime();

View File

@ -6,53 +6,7 @@ import android.graphics.Paint;
public class CircleClock extends AbstractClock {
/**
* 根据控件的大小初始化时钟刻度的长度和宽度指针的长度和宽度时钟中心点的半径
*/
protected void initClockPointerLength() {
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
mDefaultScaleLength = mRadius / 10;
mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
mParticularlyScaleLength = mRadius / 5;
mParticularlyScaleWidth = mParticularlyScaleLength / 6;
/*
* 时针长=半径/3;
* 时针宽=特殊时钟刻度宽;
*
* */
mHourPointerLength = mRadius / 3;
mHourPointerWidth = mParticularlyScaleWidth;
/*
* 分针长=半径/2;
* 分针宽=特殊时钟刻度宽;
*
* */
mMinutePointerLength = mRadius / 2;
mMinutePointerWidth = mParticularlyScaleWidth;
/*
* 秒针长=半径/3*2;
* 秒针宽=默认时钟刻度宽;
*
* */
mSecondPointerLength = mRadius / 3 * 2;
mSecondPointerWidth = mDefaultScaleWidth;
// 中心点半径=默认刻度宽+特殊刻度宽/2
mPointRadius = (mDefaultScaleWidth + mParticularlyScaleWidth) / 2;
}
/**
* 绘制时钟的圆形和刻度
*/
@ -69,14 +23,14 @@ public class CircleClock extends AbstractClock {
mDefaultPaint.setStrokeWidth(mParticularlyScaleWidth);
mDefaultPaint.setColor(mColorParticularyScale);
mDefaultPaint.setAlpha(255);
canvas.drawLine(0, -mRadius, 0, -mRadius + mParticularlyScaleLength, mDefaultPaint);
} else { // 一般时刻
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mColorDefaultScale);
mDefaultPaint.setAlpha(100);
canvas.drawLine(0, -mRadius, 0, -mRadius + mDefaultScaleLength, mDefaultPaint);
}

View File

@ -0,0 +1,43 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator;
import android.graphics.Canvas;
public class CircleTwoClock extends AbstractClock {
/**
* 绘制时钟的圆形和刻度
*/
protected void drawBorder(Canvas canvas) {
canvas.save();
canvas.translate(mCenterX, mCenterY);
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mClockColor);
canvas.drawCircle(0, 0, mRadius, mDefaultPaint);
for (int i = 0; i < 60; i++) {
if (i % 5 == 0) { // 特殊时刻
mDefaultPaint.setStrokeWidth(mParticularlyScaleWidth);
mDefaultPaint.setColor(mColorParticularyScale);
mDefaultPaint.setAlpha(255);
canvas.drawLine(0, -mRadius+mDefaultScaleWidth*1.2f, 0, -mRadius + mDefaultScaleLength+mDefaultScaleWidth*1.3f, mDefaultPaint);
} else { // 一般时刻
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mColorDefaultScale);
mDefaultPaint.setAlpha(100);
canvas.drawLine(0, -mRadius+mDefaultScaleWidth, 0, -mRadius + mDefaultScaleLength, mDefaultPaint);
}
canvas.rotate(6);
}
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth/2);
mDefaultPaint.setAlpha(100);
canvas.drawCircle(0, 0, mRadius-mDefaultScaleLength*1.5f, mDefaultPaint);
canvas.restore();
}
}

View File

@ -7,53 +7,6 @@ import android.graphics.Paint;
public class HelixClock extends AbstractClock {
/**
* 根据控件的大小初始化时钟刻度的长度和宽度指针的长度和宽度时钟中心点的半径
*/
protected void initClockPointerLength() {
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
mDefaultScaleLength = mRadius / 10;
mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
mParticularlyScaleLength = mRadius / 5;
mParticularlyScaleWidth = mParticularlyScaleLength / 6;
/*
* 时针长=半径/3;
* 时针宽=特殊时钟刻度宽;
*
* */
mHourPointerLength = mRadius / 3;
mHourPointerWidth = mParticularlyScaleWidth;
/*
* 分针长=半径/2;
* 分针宽=特殊时钟刻度宽;
*
* */
mMinutePointerLength = mRadius / 2;
mMinutePointerWidth = mParticularlyScaleWidth;
/*
* 秒针长=半径/3*2;
* 秒针宽=默认时钟刻度宽;
*
* */
mSecondPointerLength = mRadius / 3 * 2;
mSecondPointerWidth = mDefaultScaleWidth;
// 中心点半径=默认刻度宽+特殊刻度宽/2
mPointRadius = (mDefaultScaleWidth + mParticularlyScaleWidth) / 2;
}
/**
* 绘制时钟的圆形和刻度
*/

View File

@ -6,53 +6,7 @@ import android.graphics.Paint;
//六角形
public class HexagonalClock extends AbstractClock {
/**
* 根据控件的大小初始化时钟刻度的长度和宽度指针的长度和宽度时钟中心点的半径
*/
protected void initClockPointerLength() {
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
mDefaultScaleLength = mRadius / 10;
mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
mParticularlyScaleLength = mRadius / 5;
mParticularlyScaleWidth = mParticularlyScaleLength / 6;
/*
* 时针长=半径/3;
* 时针宽=特殊时钟刻度宽;
*
* */
mHourPointerLength = mRadius / 3;
mHourPointerWidth = mParticularlyScaleWidth;
/*
* 分针长=半径/2;
* 分针宽=特殊时钟刻度宽;
*
* */
mMinutePointerLength = mRadius / 2;
mMinutePointerWidth = mParticularlyScaleWidth;
/*
* 秒针长=半径/3*2;
* 秒针宽=默认时钟刻度宽;
*
* */
mSecondPointerLength = mRadius / 3 * 2;
mSecondPointerWidth = mDefaultScaleWidth;
// 中心点半径=默认刻度宽+特殊刻度宽/2
mPointRadius = (mDefaultScaleWidth + mParticularlyScaleWidth) / 2;
}
/**
* 绘制时钟的圆形和刻度
*/
@ -89,10 +43,12 @@ public class HexagonalClock extends AbstractClock {
if (j % 5 == 0) { // 特殊时刻
mDefaultPaint.setStrokeWidth(mParticularlyScaleWidth);
mDefaultPaint.setColor(mColorParticularyScale);
mDefaultPaint.setAlpha(255);
scaleLength = mParticularlyScaleLength;
} else { // 一般时刻
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mColorDefaultScale);
mDefaultPaint.setAlpha(100);
scaleLength = mDefaultScaleLength;
}
floatLength = radianTanValue * scaleLength;

View File

@ -0,0 +1,12 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator;
import android.graphics.Canvas;
import android.graphics.Paint;
public interface I_Pointer {
void init(float mRadius,int mClockColor);
void drawPointer(Canvas canvas, int mH,int mM,int mS, Paint mPointerPaint);
}

View File

@ -6,54 +6,6 @@ import android.graphics.Paint;
//八边形
public class OctagonalClock extends AbstractClock {
/**
* 根据控件的大小初始化时钟刻度的长度和宽度指针的长度和宽度时钟中心点的半径
*/
protected void initClockPointerLength() {
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
mDefaultScaleLength = mRadius / 10;
mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
mParticularlyScaleLength = mRadius / 5;
mParticularlyScaleWidth = mParticularlyScaleLength / 6;
/*
* 时针长=半径/3;
* 时针宽=特殊时钟刻度宽;
*
* */
mHourPointerLength = mRadius / 3;
mHourPointerWidth = mParticularlyScaleWidth;
/*
* 分针长=半径/2;
* 分针宽=特殊时钟刻度宽;
*
* */
mMinutePointerLength = mRadius / 2;
mMinutePointerWidth = mParticularlyScaleWidth;
/*
* 秒针长=半径/3*2;
* 秒针宽=默认时钟刻度宽;
*
* */
mSecondPointerLength = mRadius / 3 * 2;
mSecondPointerWidth = mDefaultScaleWidth;
// 中心点半径=默认刻度宽+特殊刻度宽/2
mPointRadius = (mDefaultScaleWidth + mParticularlyScaleWidth) / 2;
}
/**
* 绘制时钟的圆形和刻度
* 分三段
@ -95,10 +47,12 @@ public class OctagonalClock extends AbstractClock {
if (k % 5 == 0) { // 特殊时刻
mDefaultPaint.setStrokeWidth(mParticularlyScaleWidth);
mDefaultPaint.setColor(mColorParticularyScale);
mDefaultPaint.setAlpha(255);
scaleLength=mParticularlyScaleLength;
} else { // 一般时刻
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mColorDefaultScale);
mDefaultPaint.setAlpha(100);
scaleLength=mDefaultScaleLength;
}
floatLength=radianTanValue*scaleLength;

View File

@ -6,54 +6,6 @@ import android.graphics.Paint;
//(椭圆
public class OvalClock extends AbstractClock {
/**
* 根据控件的大小初始化时钟刻度的长度和宽度指针的长度和宽度时钟中心点的半径
*/
protected void initClockPointerLength() {
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
mDefaultScaleLength = mRadius / 10;
mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
mParticularlyScaleLength = mRadius / 5;
mParticularlyScaleWidth = mParticularlyScaleLength / 6;
/*
* 时针长=半径/3;
* 时针宽=特殊时钟刻度宽;
*
* */
mHourPointerLength = mRadius / 3;
mHourPointerWidth = mParticularlyScaleWidth;
/*
* 分针长=半径/2;
* 分针宽=特殊时钟刻度宽;
*
* */
mMinutePointerLength = mRadius / 2;
mMinutePointerWidth = mParticularlyScaleWidth;
/*
* 秒针长=半径/3*2;
* 秒针宽=默认时钟刻度宽;
*
* */
mSecondPointerLength = mRadius / 3 * 2;
mSecondPointerWidth = mDefaultScaleWidth;
// 中心点半径=默认刻度宽+特殊刻度宽/2
mPointRadius = (mDefaultScaleWidth + mParticularlyScaleWidth) / 2;
}
/**
* 绘制时钟的圆形和刻度
*/
@ -70,14 +22,14 @@ public class OvalClock extends AbstractClock {
mDefaultPaint.setStrokeWidth(mParticularlyScaleWidth);
mDefaultPaint.setColor(mColorParticularyScale);
mDefaultPaint.setAlpha(255);
canvas.drawLine(0, -mRadius, 0, -mRadius + mParticularlyScaleLength, mDefaultPaint);
} else { // 一般时刻
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mColorDefaultScale);
mDefaultPaint.setAlpha(100);
canvas.drawLine(0, -mRadius, 0, -mRadius + mDefaultScaleLength, mDefaultPaint);
}

View File

@ -6,54 +6,6 @@ import android.graphics.Paint;
//方型
public class SquareClock extends AbstractClock {
/**
* 根据控件的大小初始化时钟刻度的长度和宽度指针的长度和宽度时钟中心点的半径
*/
protected void initClockPointerLength() {
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
mDefaultScaleLength = mRadius / 10;
mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
mParticularlyScaleLength = mRadius / 5;
mParticularlyScaleWidth = mParticularlyScaleLength / 6;
/*
* 时针长=半径/3;
* 时针宽=特殊时钟刻度宽;
*
* */
mHourPointerLength = mRadius / 3;
mHourPointerWidth = mParticularlyScaleWidth;
/*
* 分针长=半径/2;
* 分针宽=特殊时钟刻度宽;
*
* */
mMinutePointerLength = mRadius / 2;
mMinutePointerWidth = mParticularlyScaleWidth;
/*
* 秒针长=半径/3*2;
* 秒针宽=默认时钟刻度宽;
*
* */
mSecondPointerLength = mRadius / 3 * 2;
mSecondPointerWidth = mDefaultScaleWidth;
// 中心点半径=默认刻度宽+特殊刻度宽/2
mPointRadius = (mDefaultScaleWidth + mParticularlyScaleWidth) / 2;
}
/**
* 绘制时钟的外型形和刻度
*/
@ -82,10 +34,12 @@ public class SquareClock extends AbstractClock {
if (j % 5 == 0) { // 特殊时刻
mDefaultPaint.setStrokeWidth(mParticularlyScaleWidth);
mDefaultPaint.setColor(mColorParticularyScale);
mDefaultPaint.setAlpha(255);
scaleLength=mParticularlyScaleLength;
} else { // 一般时刻
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mColorDefaultScale);
mDefaultPaint.setAlpha(100);
scaleLength=mDefaultScaleLength;
}
floatLength=radianTanValue*scaleLength;
@ -113,10 +67,12 @@ public class SquareClock extends AbstractClock {
if (j % 5 == 0) { // 特殊时刻
mDefaultPaint.setStrokeWidth(mParticularlyScaleWidth);
mDefaultPaint.setColor(mColorParticularyScale);
mDefaultPaint.setAlpha(255);
scaleLength=mParticularlyScaleLength;
} else { // 一般时刻
mDefaultPaint.setStrokeWidth(mDefaultScaleWidth);
mDefaultPaint.setColor(mColorDefaultScale);
mDefaultPaint.setAlpha(100);
scaleLength=mDefaultScaleLength;
}
floatLength=radianTanValue*scaleLength;
@ -127,7 +83,6 @@ public class SquareClock extends AbstractClock {
canvas.drawLine(width,startY-stepLeng, width - scaleLength,startY-stepLeng+floatLength, mDefaultPaint);
j++;
}
//}
}

View File

@ -0,0 +1,177 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
import android.graphics.Canvas;
import android.graphics.Paint;
import clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.I_Pointer;
public abstract class AbstractPointer implements I_Pointer {
protected Paint mPointerPaint;
protected float mRadius, mPointRadius,
mHourPointerLength, mHourPointerWidth,
mMinutePointerLength, mMinutePointerWidth,
mSecondPointerLength, mSecondPointerWidth;
protected int mClockColor, mColorHourPointer,mColorMinutePointer, mColorSecondPointer;
// 当前时
protected int mH, mM, mS;
@Override
public void init(float mRadius,int mClockColor) {
this.mRadius = mRadius;
this.mClockColor = mClockColor;
mColorHourPointer=mColorMinutePointer=mColorSecondPointer=mClockColor;
initPaint();
initPointerLength(mRadius);
}
public void initPaint(){
mPointerPaint = new Paint();
mPointerPaint.setAntiAlias(true);
mPointerPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPointerPaint.setStrokeCap(Paint.Cap.ROUND);
mPointerPaint.setColor(mClockColor);
}
public void initPointerLength(float mRadius){
/*
* 默认时钟刻度长=半径/10;
* 默认时钟刻度宽=/6;
*
* */
float mDefaultScaleLength = mRadius / 10;
float mDefaultScaleWidth = mDefaultScaleLength / 6;
/*
* 特殊时钟刻度长=半径/5;
* 特殊时钟刻度宽=/6;
*
* */
float mParticularlyScaleLength = mRadius / 5;
float mParticularlyScaleWidth = mParticularlyScaleLength / 6;
/*
* 时针长=半径/3;
* 时针宽=特殊时钟刻度宽;
*
* */
mHourPointerLength = mRadius / 3;
mHourPointerWidth = mParticularlyScaleWidth;
/*
* 分针长=半径/2;
* 分针宽=特殊时钟刻度宽;
*
* */
mMinutePointerLength = mRadius / 2;
mMinutePointerWidth = mParticularlyScaleWidth;
/*
* 秒针长=半径/3*2;
* 秒针宽=默认时钟刻度宽;
*
* */
mSecondPointerLength = mRadius / 3 * 2;
mSecondPointerWidth = mDefaultScaleWidth;
// 中心点半径=默认刻度宽+特殊刻度宽/2
mPointRadius = (mDefaultScaleWidth + mParticularlyScaleWidth) / 2;
}
/**
* 绘制指针
*/
public void drawPointer(Canvas canvas, int mH,int mM,int mS, Paint paint) {
this.mH=mH;
this.mM=mM;
this.mS=mS;
drawHourPointer(canvas);
drawMinutePointer(canvas);
drawSecondPointer(canvas);
drawCenterCircle(canvas);
}
// 绘制中心原点需要在指针绘制完成后才能绘制
protected void drawCenterCircle(Canvas canvas){
canvas.drawCircle(0, 0, mPointRadius, mPointerPaint);
}
/**
* 绘制时针
*/
protected void drawHourPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mHourPointerWidth);
mPointerPaint.setColor(mColorHourPointer);
// 当前时间的总秒数
float s = mH * 60 * 60 + mM * 60 + mS;
// 百分比
float percentage = s / (12 * 60 * 60);
// 通过角度计算弧度值因为时钟的角度起线是y轴负方向而View角度的起线是x轴正方向所以要加270度
float angle = calcAngle(percentage);
float x = calcX(mHourPointerLength , angle);
float y = calcY(mHourPointerLength , angle);
canvas.drawLine(0, 0, x, y, mPointerPaint);
}
/**
* 绘制分针
*/
protected void drawMinutePointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mMinutePointerWidth);
mPointerPaint.setColor(mColorMinutePointer);
float s = mM * 60 + mS;
float percentage = s / (60 * 60);
float angle = calcAngle(percentage);
float x = calcX(mMinutePointerLength , angle);
float y = calcY(mMinutePointerLength , angle);
canvas.drawLine(0, 0, x, y, mPointerPaint);
}
/**
* 绘制秒针
*/
protected void drawSecondPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mSecondPointerWidth);
mPointerPaint.setColor(mColorSecondPointer);
float s = mS;
float percentage = s / 60;
float angle = calcAngle(percentage);
float x = calcX(mSecondPointerLength , angle);
float y = calcY(mSecondPointerLength , angle);
canvas.drawLine(0, 0, x, y, mPointerPaint);
}
protected float calcAngle(float percentage){
return 270 + 360 * percentage;
}
protected float calcX(float baseLength,float angle){
return (float)(baseLength * Math.cos(Math.PI * 2 / 360 * angle));
}
protected float calcY(float baseLength,float angle){
return (float) (baseLength * Math.sin(Math.PI * 2 / 360 * angle));
}
}

View File

@ -0,0 +1,5 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
public class DefaultPointer extends AbstractPointer {
}

View File

@ -0,0 +1,73 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
import android.graphics.Canvas;
import android.graphics.Path;
public class LeafPointer extends SecondTailPointer {
@Override
public void initPointerLength(float mRadius) {
super.initPointerLength(mRadius);
mMinutePointerWidth=mMinutePointerWidth/3;
}
@Override
protected void drawHourPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mHourPointerWidth);
mPointerPaint.setColor(mColorHourPointer);
// 当前时间的总秒数
float s = mH * 60 * 60 + mM * 60 + mS;
// 百分比
float percentage = s / (12 * 60 * 60);
// 通过角度计算弧度值因为时钟的角度起线是y轴负方向而View角度的起线是x轴正方向所以要加270度
float angle = calcAngle(percentage);
float x = calcX(mHourPointerLength, angle);
float y = calcY(mHourPointerLength, angle);
float minLength = mHourPointerLength / 2;
float x1 = calcX(minLength, angle + 20);
float y1 = calcY(minLength, angle + 20);
float x2 = calcX(minLength, angle - 20);
float y2 = calcY(minLength, angle - 20);
Path path = new Path();
path.cubicTo(0, 0, x1, y1, x, y);
path.cubicTo(x, y, x2, y2, 0, 0);
canvas.drawPath(path, mPointerPaint);
}
@Override
protected void drawMinutePointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mMinutePointerWidth);
mPointerPaint.setColor(mColorMinutePointer);
float s = mM * 60 + mS;
float percentage = s / (60 * 60);
float angle = calcAngle(percentage);
float x = calcX(mMinutePointerLength, angle);
float y = calcY(mMinutePointerLength, angle);
float minLength = mMinutePointerLength / 2;
float x1 = calcX(minLength, angle + 10);
float y1 = calcY(minLength, angle + 10);
float x2 = calcX(minLength, angle - 10);
float y2 = calcY(minLength, angle - 10);
Path path = new Path();
path.cubicTo(0, 0, x1, y1, x, y);
path.cubicTo(x, y, x2, y2, 0, 0);
canvas.drawPath(path, mPointerPaint);
}
}

View File

@ -0,0 +1,72 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
import android.graphics.Canvas;
import android.graphics.Path;
public class LeafTwoPointer extends SecondTailPointer {
@Override
public void initPointerLength(float mRadius) {
super.initPointerLength(mRadius);
mMinutePointerWidth=mMinutePointerWidth/3;
}
@Override
protected void drawHourPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mHourPointerWidth);
mPointerPaint.setColor(mColorHourPointer);
// 当前时间的总秒数
float s = mH * 60 * 60 + mM * 60 + mS;
// 百分比
float percentage = s / (12 * 60 * 60);
// 通过角度计算弧度值因为时钟的角度起线是y轴负方向而View角度的起线是x轴正方向所以要加270度
float angle = calcAngle(percentage);
float x = calcX(mHourPointerLength, angle);
float y = calcY(mHourPointerLength, angle);
float minLength = mHourPointerLength / 2;
float x1 = calcX(minLength, angle + 20);
float y1 = calcY(minLength, angle + 20);
float x2 = calcX(minLength, angle - 20);
float y2 = calcY(minLength, angle - 20);
Path path = new Path();
path.cubicTo(0, 0, x1, y1, x, y);
path.cubicTo(0, 0, x2, y2,x, y );
canvas.drawPath(path, mPointerPaint);
}
@Override
protected void drawMinutePointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mMinutePointerWidth);
mPointerPaint.setColor(mColorMinutePointer);
float s = mM * 60 + mS;
float percentage = s / (60 * 60);
float angle = calcAngle(percentage);
float x = calcX(mMinutePointerLength, angle);
float y = calcY(mMinutePointerLength, angle);
float minLength = mMinutePointerLength / 2;
float x1 = calcX(minLength, angle + 10);
float y1 = calcY(minLength, angle + 10);
float x2 = calcX(minLength, angle - 10);
float y2 = calcY(minLength, angle - 10);
Path path = new Path();
path.cubicTo(0, 0, x1, y1, x, y);
path.cubicTo(0, 0,x2, y2, x, y);
canvas.drawPath(path, mPointerPaint);
}
}

View File

@ -0,0 +1,40 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
import android.graphics.Canvas;
import android.graphics.Color;
public class SecondTailPointer extends AbstractPointer{
@Override
public void initPointerLength(float mRadius) {
super.initPointerLength(mRadius);
mHourPointerLength = mRadius / 8*4.5f;
mMinutePointerLength = mRadius / 8*6;
mSecondPointerLength = mRadius / 8 * 7;
}
@Override
protected void drawCenterCircle(Canvas canvas) {
super.drawCenterCircle(canvas);
mPointerPaint.setColor(Color.BLACK);
canvas.drawCircle(0, 0, mPointRadius/2, mPointerPaint);
}
@Override
protected void drawSecondPointer(Canvas canvas) {
super.drawSecondPointer(canvas);
mPointerPaint.setStrokeWidth(mSecondPointerWidth*1.5f);
float s = mS;
float percentage = s / 60;
float angle = calcAngle(percentage)+180;
float x = calcX(mSecondPointerLength/5 , angle);
float y = calcY(mSecondPointerLength/5 , angle);
canvas.drawLine(0, 0, x, y, mPointerPaint);
canvas.drawCircle(0,0,mSecondPointerWidth*2,mPointerPaint);
}
}

View File

@ -0,0 +1,99 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
import android.graphics.Canvas;
import android.graphics.Path;
public class SwordPointer extends SecondTailPointer{
@Override
public void initPointerLength(float mRadius) {
super.initPointerLength(mRadius);
mHourPointerWidth=mHourPointerWidth/4;
mMinutePointerWidth=mMinutePointerWidth/4;
}
@Override
protected void drawHourPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mHourPointerWidth);
mPointerPaint.setColor(mColorHourPointer);
// 当前时间的总秒数
float s = mH * 60 * 60 + mM * 60 + mS;
// 百分比
float percentage = s / (12 * 60 * 60);
// 通过角度计算弧度值因为时钟的角度起线是y轴负方向而View角度的起线是x轴正方向所以要加270度
float angle = calcAngle(percentage);
float x = calcX(mHourPointerLength , angle);
float y = calcY(mHourPointerLength , angle);
float minLength=mHourPointerLength*4/5;
float x3 = calcX(minLength , angle+10);
float y3 = calcY(minLength , angle+10);
float x4 = calcX(minLength , angle-10);
float y4 = calcY(minLength , angle-10);
minLength=mHourPointerLength/5;
float x1=calcX(minLength , angle+180+20);
float y1 = calcY(minLength , angle+180+20);
float x2=calcX(minLength, angle+180-20);
float y2 = calcY(minLength , angle+180-20);
Path path=new Path();
path.lineTo(x1,y1);
path.lineTo(x2,y2);
path.lineTo(0,0);
path.lineTo(x3,y3);
path.lineTo(x,y);
path.lineTo(x4,y4);
path.lineTo(0,0);
canvas.drawPath(path,mPointerPaint);
}
@Override
protected void drawMinutePointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mMinutePointerWidth);
mPointerPaint.setColor(mColorMinutePointer);
float s = mM * 60 + mS;
float percentage = s / (60 * 60);
float angle = calcAngle(percentage);
float x = calcX(mMinutePointerLength , angle);
float y = calcY(mMinutePointerLength , angle);
float minLength=mMinutePointerLength*4/5;
float x3 = calcX(minLength , angle+6);
float y3 = calcY(minLength , angle+6);
float x4 = calcX(minLength , angle-6);
float y4 = calcY(minLength , angle-6);
minLength=mMinutePointerLength/5;
float x1=calcX(minLength , angle+180+10);
float y1 = calcY(minLength , angle+180+10);
float x2=calcX(minLength, angle+180-10);
float y2 = calcY(minLength , angle+180-10);
Path path=new Path();
path.lineTo(x1,y1);
path.lineTo(x2,y2);
path.lineTo(0,0);
path.lineTo(x3,y3);
path.lineTo(x,y);
path.lineTo(x4,y4);
path.lineTo(0,0);
canvas.drawPath(path,mPointerPaint);
}
}

View File

@ -0,0 +1,71 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
import android.graphics.Canvas;
import android.graphics.Path;
public class TrianglePointer extends SecondTailPointer{
@Override
protected void drawHourPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mHourPointerWidth);
mPointerPaint.setColor(mColorHourPointer);
// 当前时间的总秒数
float s = mH * 60 * 60 + mM * 60 + mS;
// 百分比
float percentage = s / (12 * 60 * 60);
// 通过角度计算弧度值因为时钟的角度起线是y轴负方向而View角度的起线是x轴正方向所以要加270度
float angle = calcAngle(percentage);
float x = calcX(mHourPointerLength , angle);
float y = calcY(mHourPointerLength , angle);
float minLength=mHourPointerLength/5;
float x1=calcX(minLength , angle+180+20);
float y1 = calcY(minLength , angle+180+20);
float x2=calcX(minLength, angle+180-20);
float y2 = calcY(minLength , angle+180-20);
Path path=new Path();
path.moveTo(x1,y1);
path.lineTo(x2,y2);
path.lineTo(x,y);
path.lineTo(x1,y1);
canvas.drawPath(path,mPointerPaint);
}
@Override
protected void drawMinutePointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mMinutePointerWidth);
mPointerPaint.setColor(mColorMinutePointer);
float s = mM * 60 + mS;
float percentage = s / (60 * 60);
float angle = calcAngle(percentage);
float x = calcX(mMinutePointerLength , angle);
float y = calcY(mMinutePointerLength , angle);
float minLength=mMinutePointerLength/5;
float x1=calcX(minLength , angle+180+20);
float y1 = calcY(minLength , angle+180+20);
float x2=calcX(minLength, angle+180-20);
float y2 = calcY(minLength , angle+180-20);
Path path=new Path();
path.moveTo(x1,y1);
path.lineTo(x2,y2);
path.lineTo(x,y);
path.lineTo(x1,y1);
canvas.drawPath(path,mPointerPaint);
}
}

View File

@ -0,0 +1,56 @@
package clock.socoolby.com.clock.widget.animatorview.animator.clockanimator.pointer;
import android.graphics.Canvas;
public class TwoStepPointer extends SecondTailPointer{
/**
* 绘制时针
*/
protected void drawHourPointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mHourPointerWidth*2);
mPointerPaint.setColor(mColorHourPointer);
// 当前时间的总秒数
float s = mH * 60 * 60 + mM * 60 + mS;
// 百分比
float percentage = s / (12 * 60 * 60);
// 通过角度计算弧度值因为时钟的角度起线是y轴负方向而View角度的起线是x轴正方向所以要加270度
float angle = calcAngle(percentage);
float x = calcX(mHourPointerLength , angle);
float y = calcY(mHourPointerLength , angle);
float x1 = calcX(mHourPointerLength/4 , angle);
float y1 = calcY(mHourPointerLength/4 , angle);
canvas.drawLine(x1, y1, x, y, mPointerPaint);
mPointerPaint.setStrokeWidth(mHourPointerWidth/4);
canvas.drawLine(0,0,x1, y1, mPointerPaint);
}
/**
* 绘制分针
*/
protected void drawMinutePointer(Canvas canvas) {
mPointerPaint.setStrokeWidth(mMinutePointerWidth*2);
mPointerPaint.setColor(mColorMinutePointer);
float s = mM * 60 + mS;
float percentage = s / (60 * 60);
float angle = calcAngle(percentage);
float x = calcX(mMinutePointerLength , angle);
float y = calcY(mMinutePointerLength , angle);
float x1 = calcX(mMinutePointerLength/4 , angle);
float y1 = calcY(mMinutePointerLength/4 , angle);
canvas.drawLine(x1, y1, x, y, mPointerPaint);
mPointerPaint.setStrokeWidth(mMinutePointerWidth/4);
canvas.drawLine(0,0,x1, y1, mPointerPaint);
}
}

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.text.TextPaint;
@ -12,8 +13,15 @@ import android.util.AttributeSet;
import android.util.Log;
import androidx.annotation.Nullable;
import java.util.HashMap;
import java.util.Random;
import clock.socoolby.com.clock.widget.textview.charanimator.AbstractCharAnimator;
import clock.socoolby.com.clock.widget.textview.charanimator.CharAnimatorEnum;
import clock.socoolby.com.clock.widget.textview.charanimator.Down2UpCharAnimator;
import clock.socoolby.com.clock.widget.textview.charanimator.Marquee3DCharAnimator;
import clock.socoolby.com.clock.widget.textview.charanimator.Up2DownCharAnimator;
public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
public static final String Tag=DigitTextView.class.getSimpleName();
@ -29,6 +37,8 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
int textWidth=0;
private CharSequence preString=null;
public DigitTextView(Context context) {
super(context);
}
@ -49,10 +59,13 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
boolean isLinearGradientPosAble=false;
boolean isReflectedAble=false;
public void setLinearGradientRandom(boolean able){
if(able){
linearGradientColors= new int[]{roundColor(), roundColor(), roundColor(), roundColor(), roundColor(), roundColor(), roundColor()};
isLinearGradientPosAble=rand.nextBoolean();
isReflectedAble=rand.nextBoolean();
}
setLinearGradientAble(able);
setShadowType(rand.nextInt(3));
@ -83,8 +96,9 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
case 1://阴影效果
setShadowLayer(4, 10, 10, Color.BLACK);
break;
case 2://浮雕效果
setShadowLayer(1, 0.5f, 0.5f, Color.argb(200,204,204,204));
case 2:
//setShadowLayer(1, 0.5f, 0.5f, Color.argb(200,204,204,204));//浮雕效果
setShadowLayer(10, 0, 0, Color.parseColor("#FF4141"));//边缘模糊
break;
default:
setShadowLayer(0,0,0,getPaint().getColor());
@ -115,6 +129,25 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
this.linearGradientColors = linearGradientColors;
}
public CharAnimatorEnum getCurrentCharAnimatorType() {
return currentCharAnimatorType;
}
public void setCurrentCharAnimatorType(CharAnimatorEnum currentCharAnimatorType) {
this.currentCharAnimatorType = currentCharAnimatorType;
}
private int textHight;
private int baseCharWidth;
private int flagCharwidth;
private int smallTextHight;
private int smallCharWidth;
private int textLength;
private int textSmallSpan;
private HashMap<Integer, AbstractCharAnimator> charAnimatorHashMap=new HashMap<>();
private CharAnimatorEnum currentCharAnimatorType= CharAnimatorEnum.Marquee3D_Up;
protected void onDraw(Canvas canvas) {
int color = getCurrentTextColor();
@ -126,15 +159,15 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
Paint.FontMetricsInt fm=mTextPaint.getFontMetricsInt();
int baseCharWidth= getCharWidth("8",mTextPaint);
int flagCharwidth=getCharWidth(":",mTextPaint);
int textHight=-fm.descent - fm.ascent;
int smallTextHight=0;
int smallCharWidth=0;
baseCharWidth= getCharWidth("8",mTextPaint);
flagCharwidth=getCharWidth(":",mTextPaint);
textHight=-fm.descent - fm.ascent;
smallTextHight=0;
smallCharWidth=0;
Paint smallCharPaint=null;
int textLength=textToDraw.length();
int textSmallSpan=0;
textLength=textToDraw.length();
textSmallSpan=0;
if(textLength>4){
textWidth=baseCharWidth*4+flagCharwidth;
@ -152,6 +185,8 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
float startX=(getWidth()-textWidth-textSmallSpan)/2;
float startY=(getHeight()+textHight)/2;
AbstractCharAnimator charAnimator;
for(int i=0;i<textLength;i++){
String c=String.valueOf(textToDraw.charAt(i));
if(i<5){
@ -160,7 +195,24 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
startX+=flagCharwidth;
}else{
int charWidth= getCharWidth(c,mTextPaint);
canvas.drawText(c, startX+(baseCharWidth-charWidth)/2, startY+baseLineDown, mTextPaint);
if(currentCharAnimatorType!= CharAnimatorEnum.NOSETUP) {
charAnimator = charAnimatorHashMap.get(i);
if (charAnimator != null && !charAnimator.isCharAnimatorRuning()) {
charAnimatorHashMap.remove(i);
charAnimator=null;
}
if (charAnimator == null&&preString != null&&preString.length()==textToDraw.length() && textToDraw.charAt(i) != preString.charAt(i)) {
charAnimator=createCharAnimator(String.valueOf(preString.charAt(i)), c, currentCharAnimatorType);
charAnimatorHashMap.put(i, charAnimator);
}
if (charAnimator != null) {
charAnimator.drawCharAnimator(canvas, startX + (baseCharWidth - charWidth) / 2, startY + baseLineDown, mTextPaint);
Log.d(Tag,"charAnimator index i:"+i+"\tanimator percent:");
invalidate();
}else
drawChar(canvas, c, startX + (baseCharWidth - charWidth) / 2, startY + baseLineDown, mTextPaint);
}else
drawChar(canvas, c, startX + (baseCharWidth - charWidth) / 2, startY + baseLineDown, mTextPaint);
startX+=baseCharWidth;
}
}else if(i==5) {
@ -168,11 +220,54 @@ public class DigitTextView extends android.support.v7.widget.AppCompatTextView {
} else {
float centerY=(getHeight()+smallTextHight)/2;
centerY=centerY+(startY-centerY)/2+smallCharPaint.getFontMetrics().descent;
canvas.drawText(c, startX, centerY+baseLineDown, smallCharPaint);
drawChar(canvas,c, startX, centerY+baseLineDown, smallCharPaint);
startX+=smallCharWidth;
//Log.d(Tag,"view hight:"+getHeight()+"\t startY:"+startY+"\t text hight:"+textHight+"small text hight:"+smallTextHight);
}
}
preString=textToDraw;
}
private void drawChar(Canvas canvas,String c,float startX,float startY,Paint mTextPaint){
if(isReflectedAble)
drawCharReflected(canvas,c, startX, startY, mTextPaint);
canvas.drawText(c, startX, startY, mTextPaint);
}
private void drawCharReflected(Canvas canvas,String c,float startX,float startY,Paint mTextPaint){
canvas.save();
Paint paint = new Paint(mTextPaint);
LinearGradient shader = new LinearGradient(startX,
-startY, startX,
-startY-textHight*6/5,
Color.BLACK, 0x00ffffff, Shader.TileMode.MIRROR);// 创建线性渐变LinearGradient对象
Matrix matrix = new Matrix();
matrix.preScale(1, -1); // 实现图片的反转
paint.setShader(shader); // 绘制
paint.setAlpha(50);
canvas.setMatrix(matrix);
canvas.drawText(c, startX, -startY, paint);
canvas.restore();
}
private AbstractCharAnimator createCharAnimator(String preString, String currentString, CharAnimatorEnum type){
AbstractCharAnimator charAnimator=null;
switch (type){
case DOWN2UP:
charAnimator= new Down2UpCharAnimator(preString,currentString);
break;
case UP2DOWN:
charAnimator= new Up2DownCharAnimator(preString,currentString);
break;
case Marquee3D_Up:
charAnimator=new Marquee3DCharAnimator(preString,currentString,Marquee3DCharAnimator.D2U);
break;
case Marquee3D_Down:
charAnimator=new Marquee3DCharAnimator(preString,currentString,Marquee3DCharAnimator.U2D);
break;
}
return charAnimator;
}
/**

View File

@ -0,0 +1,38 @@
package clock.socoolby.com.clock.widget.textview.charanimator;
import android.graphics.Canvas;
import android.graphics.Paint;
public abstract class AbstractCharAnimator {
protected boolean charAnimatorRuning;
protected float charAnimatorPercent;
protected String preString,currentString;
public AbstractCharAnimator(String preString, String currentString) {
this.preString = preString;
this.currentString = currentString;
charAnimatorRuning=true;
charAnimatorPercent=0f;
}
public void drawCharAnimator(Canvas canvas, float startX, float startY, Paint mTextPaint){
drawCharPre(canvas, preString, startX, startY, mTextPaint,charAnimatorPercent);
drawCharCurrent(canvas, currentString, startX, startY, mTextPaint,charAnimatorPercent);
move();
}
public abstract void drawCharPre(Canvas canvas,String strToDraw, float startX, float startY, Paint mTextPaint,final float percent);
public abstract void drawCharCurrent(Canvas canvas,String strToDraw, float startX, float startY, Paint mTextPaint,final float percent);
public void move(){
charAnimatorPercent+=0.05f;
if(charAnimatorPercent>1)
charAnimatorRuning=false;
}
public boolean isCharAnimatorRuning() {
return charAnimatorRuning;
}
}

View File

@ -0,0 +1,5 @@
package clock.socoolby.com.clock.widget.textview.charanimator;
public enum CharAnimatorEnum{
NOSETUP,UP2DOWN,DOWN2UP,Marquee3D_Up,Marquee3D_Down;
}

View File

@ -0,0 +1,21 @@
package clock.socoolby.com.clock.widget.textview.charanimator;
import android.graphics.Canvas;
import android.graphics.Paint;
public class Down2UpCharAnimator extends AbstractCharAnimator {
public Down2UpCharAnimator(String preString, String currentString) {
super(preString, currentString);
}
@Override
public void drawCharPre(Canvas canvas, String strToDraw, float startX, float startY, Paint mTextPaint, float percent) {
canvas.drawText(strToDraw, startX, startY-startY*percent, mTextPaint);
}
@Override
public void drawCharCurrent(Canvas canvas, String strToDraw, float startX, float startY, Paint mTextPaint, float percent) {
canvas.drawText(strToDraw, startX, 2*startY-startY*percent, mTextPaint);
}
}

View File

@ -0,0 +1,113 @@
package clock.socoolby.com.clock.widget.textview.charanimator;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
//参考https://github.com/xiangcman/Marquee3DView
public class Marquee3DCharAnimator extends AbstractCharAnimator {
//从下到上进行旋转滚动
public static final int D2U = 1;
//从上到下进行旋转滚动
public static final int U2D = 2;
//负责围绕那个轴进行旋转
private Camera camera;
//负责控制旋转点
private Matrix matrix;
private float changeRotate;
private float translateY;
private int direction;
public Marquee3DCharAnimator(String preString, String currentString,int direction) {
super(preString, currentString);
this.direction=direction;
initialize();
}
private void initialize() {
camera = new Camera();
matrix = new Matrix();
}
@Override
public void move() {
super.move();
changeRotate = 90*charAnimatorPercent;
}
@Override
public void drawCharPre(Canvas canvas, String strToDraw, float startX, float startY, Paint mTextPaint, float percent) {
//从0到height的一个过程
translateY = startY *charAnimatorPercent;
int alpha = (int) (255 - percent * 255);
mTextPaint.setAlpha(alpha);
float width=startX;
float height=startY;
canvas.save();
camera.save();
if (direction == D2U) {
//当前的item是往里面转动的因此角度是增大的
camera.rotateX(changeRotate);//0到90度的过程
} else {
camera.rotateX(-changeRotate);
}
camera.getMatrix(matrix);
camera.restore();
if (direction == D2U) {
matrix.preTranslate(-width / 2, -height);
matrix.postTranslate(width / 2, height - translateY);//最后跑到0的位置了
} else {
matrix.preTranslate(-width / 2, 0);
matrix.postTranslate(width / 2, translateY);
}
canvas.setMatrix(matrix);
canvas.drawText(strToDraw, startX, startY, mTextPaint);
canvas.restore();
}
@Override
public void drawCharCurrent(Canvas canvas, String strToDraw, float startX, float startY, Paint mTextPaint, float percent) {
translateY = startY *charAnimatorPercent;
float width=startX;
float height=startY;
int alpha = (int) (percent * 255);
mTextPaint.setAlpha(alpha);
canvas.save();
camera.save();
if (direction == D2U) {
//-90度到0度的过程
camera.rotateX(-90 + changeRotate);
} else {
//从上到下是90度到0度的过程
camera.rotateX(90 - changeRotate);
}
camera.getMatrix(matrix);
camera.restore();
if (direction == D2U) {
matrix.preTranslate(-width / 2, 0);
matrix.postTranslate(width / 2, height + (-translateY));
} else {
matrix.preTranslate(-width / 2, -height);
matrix.postTranslate(width / 2, translateY);
}
canvas.setMatrix(matrix);
canvas.drawText(strToDraw, startX, startY, mTextPaint);
canvas.restore();
}
}

View File

@ -0,0 +1,21 @@
package clock.socoolby.com.clock.widget.textview.charanimator;
import android.graphics.Canvas;
import android.graphics.Paint;
public class Up2DownCharAnimator extends AbstractCharAnimator {
public Up2DownCharAnimator(String preString, String currentString) {
super(preString, currentString);
}
@Override
public void drawCharPre(Canvas canvas, String strToDraw, float startX, float startY, Paint mTextPaint, float percent) {
canvas.drawText(strToDraw, startX, startY+startY*percent, mTextPaint);
}
@Override
public void drawCharCurrent(Canvas canvas, String strToDraw, float startX, float startY, Paint mTextPaint, float percent) {
canvas.drawText(strToDraw, startX, startY*percent, mTextPaint);
}
}

View File

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M3.7526,0.8136c-0.6062,0.1332 -0.7349,0.2251 -1.9243,1.4054c-0.6521,0.6475 -1.1666,1.194 -1.2538,1.3411c-0.078,0.1332 -0.1884,0.4042 -0.2388,0.6017c-0.2206,0.859 -0.101,1.1666 0.7992,2.0806c0.3262,0.3353 0.6154,0.6108 0.643,0.6108c0.0643,-0 4.5744,-4.5101 4.5744,-4.5744c0,-0.0734 -1.0426,-1.0747 -1.295,-1.2492c-0.4183,-0.2849 -0.7399,-0.3401 -1.3046,-0.216Z"
android:fillColor="#FFF"/>
<path
android:pathData="M19.2895,0.8321c-0.1241,0.0504 -0.2986,0.1469 -0.3905,0.2158c-0.2388,0.179 -1.2492,1.1758 -1.2492,1.2355c0,0.0643 4.5101,4.5696 4.5742,4.5696c0.0276,-0 0.3168,-0.2755 0.6475,-0.6108c0.8957,-0.9139 1.0104,-1.2262 0.7946,-2.076c-0.0504,-0.1975 -0.1469,-0.4546 -0.2112,-0.5695c-0.1517,-0.2573 -2.1677,-2.3009 -2.4526,-2.4847c-0.4958,-0.312 -1.2996,-0.4452 -1.7129,-0.2798Z"
android:fillColor="#FFF"/>
<path
android:pathData="M10.5084,2.3981c-2.1494,0.3307 -4.014,1.2446 -5.5618,2.7235c-2.7326,2.6086 -3.7937,6.4663 -2.7924,10.1268c0.2388,0.8726 0.7118,1.9428 1.2079,2.7418c0.0506,0.0826 -0.0458,0.3262 -0.7716,1.9702l-0.8314,1.8739l0,0.7073l0,0.7073l0.7118,-0l0.7118,-0l1.4698,-1.1712c0.8083,-0.643 1.4789,-1.1712 1.4926,-1.1712c0.0091,-0 0.179,0.1056 0.3766,0.2342c0.473,0.3122 1.5293,0.822 2.1079,1.0195c1.1393,0.395 2.1175,0.5558 3.3713,0.5558c0.9691,-0 1.5799,-0.0689 2.4341,-0.2803c0.9967,-0.2388 2.0988,-0.7073 2.9578,-1.2446c0.2479,-0.1562 0.4594,-0.2849 0.4685,-0.2849c0.0091,-0 0.6797,0.5282 1.488,1.1712l1.4698,1.1712l0.7118,-0l0.7118,-0l0,-0.7073l0,-0.7027l-0.8311,-1.8785l-0.8316,-1.878l0.0826,-0.1378c0.9552,-1.6075 1.4146,-3.0449 1.5341,-4.7626c0.2479,-3.6511 -1.4789,-7.1232 -4.579,-9.2129c-0.9185,-0.6199 -2.2366,-1.1803 -3.3571,-1.4282c-1.1251,-0.2527 -2.6638,-0.3079 -3.7522,-0.1426ZM12.6946,4.8782c1.8691,0.193 3.3938,0.9139 4.7074,2.2229c1.3502,1.3502 2.0666,2.9026 2.232,4.836c0.115,1.3457 -0.1195,2.5949 -0.7255,3.8717c-1.0517,2.2044 -3.0494,3.743 -5.4883,4.2346c-0.7531,0.1469 -2.0806,0.1469 -2.8337,-0c-3.2239,-0.6478 -5.6443,-3.1416 -6.1634,-6.3473c-0.2434,-1.511 0.0322,-3.2378 0.7394,-4.6433c0.7164,-1.4376 2.0851,-2.7739 3.5364,-3.4582c1.2538,-0.5971 2.6683,-0.8496 3.9958,-0.7164Z"
android:fillColor="#FFF"/>
<path
android:pathData="M11.4499,5.8886c-3.0221,0.2479 -5.447,2.489 -6.0026,5.5342c-0.101,0.5556 -0.101,1.6534 0,2.2138c0.2525,1.3824 0.8635,2.549 1.8691,3.5549c0.9691,0.9691 2.0345,1.5478 3.3986,1.837c0.6384,0.1378 1.8324,0.1471 2.4571,0.023c2.448,-0.4822 4.3675,-2.154 5.1391,-4.4825c0.2342,-0.7073 0.3168,-1.2401 0.3168,-2.0438c0,-1.6258 -0.5098,-3.0403 -1.5614,-4.3034c-1.3502,-1.6212 -3.4812,-2.5078 -5.6167,-2.333ZM12.5062,9.7006l0,2.8015l0.2525,-0l0.2527,-0l0,0.2527l0,0.2525l0.2525,-0l0.2525,-0l0,0.2527l0,0.2527l0.2527,-0l0.2479,-0l0.0137,0.2618l0.0137,0.2664l0.2664,0.0137l0.2618,0.0139l0,0.2474l0,0.2525l0.2525,-0l0.2527,-0l0,0.5052l0,0.5052l-0.505,-0l-0.5052,-0l0,-0.2525l0,-0.2479l-0.2618,-0.0137l-0.2664,-0.0137l-0.0137,-0.2388l-0.0137,-0.2388l-0.2388,-0.0139l-0.2388,-0.0137l-0.0137,-0.2388l-0.0137,-0.2388l-0.239,-0.0139l-0.2388,-0.0137l-0.0137,-0.2664l-0.0137,-0.2618l-0.2479,-0l-0.2525,-0l0,-0.2527l0,-0.2527l-0.2525,-0l-0.2525,-0l0,-3.054l0,-3.054l0.5052,-0l0.5052,-0l0,2.8015Z"
android:fillColor="#FFF"/>
</vector>

View File

@ -1,5 +1,5 @@
<vector android:height="32dp" android:viewportHeight="1000"
android:viewportWidth="1000" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android">
<vector android:height="24dp" android:viewportHeight="1000"
android:viewportWidth="1000" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFF" android:pathData="M377.54,13.12c-15.63,8.11 -17.8,16.82 -18,66.87c0,41.74 1.58,50.45 10.29,59.74c8.11,8.31 18.6,10.48 52.03,10.48l26.71,-0l0,15.83l0,15.63l-7.32,1.19c-32.84,5.54 -64.49,13.85 -89.02,23.54c-6.92,2.77 -12.86,3.96 -13.65,2.97c-2.57,-4.35 -14.84,-8.31 -39.96,-12.86c-32.64,-5.74 -45.7,-5.94 -60.54,-0.79c-16.42,5.54 -21.96,9.5 -52.23,36.8c-35.61,32.25 -45.11,45.3 -50.05,67.66c-2.57,12.86 2.37,70.23 6.92,79.13c3.17,6.13 3.17,6.53 -6.53,25.52c-28.29,56.57 -41.74,114.93 -41.74,180.61c0,138.68 68.65,264.5 185.96,340.86c45.9,29.67 98.72,50.05 157.27,60.14c27.7,4.75 96.94,4.75 124.63,-0c44.71,-7.72 80.52,-19.39 118.7,-38.38c89.02,-44.51 157.87,-119.09 195.85,-211.87c18.79,-46.29 28.69,-98.13 28.69,-151.74c0,-64.89 -13.45,-123.05 -41.74,-179.63c-9.69,-18.99 -9.69,-19.39 -6.53,-25.52c2.18,-4.15 4.16,-17.41 6.13,-38.77c2.77,-31.65 2.57,-33.04 -1.19,-46.09c-2.37,-7.32 -7.52,-18.2 -11.47,-24.13c-7.52,-11.28 -58.16,-58.95 -70.63,-66.47c-11.27,-7.12 -28.69,-12.07 -41.54,-12.07c-24.73,-0 -73.2,11.08 -77.15,17.61c-0.59,0.99 -8.9,-1.19 -18.4,-4.75c-21.76,-8.11 -49.85,-15.83 -72.41,-19.78c-9.69,-1.58 -18.4,-3.36 -19.39,-4.15c-0.99,-0.59 -1.78,-7.52 -1.78,-15.63l0,-14.64l7.12,-1.39c3.96,-0.79 13.06,-0.79 20.58,-0.4c7.32,0.59 20.77,0.4 29.67,-0.4c14.64,-1.19 16.62,-1.98 22.75,-7.91c9.69,-9.5 11.28,-19.98 10.48,-67.85c-0.59,-43.92 -1.78,-48.47 -14.04,-57.57c-5.54,-4.15 -7.12,-4.15 -123.64,-4.75c-109.4,-0.41 -118.69,-0.21 -124.83,2.96ZM555.99,308.28c26.11,5.54 46.09,12.46 69.24,24.14c27.1,13.45 46.69,27.3 69.44,49.26c25.92,25.12 42.14,47.08 57.57,78.14c20.76,41.94 29.27,78.54 29.27,125.62c0,43.92 -8.7,82.1 -27.3,121.47c-17.41,36.8 -52.42,79.53 -84.87,103.47c-38.18,28.29 -85.07,47.68 -131.36,54.2c-21.56,2.97 -75.57,1.19 -95.16,-3.16c-114.54,-25.52 -200.01,-113.95 -220.98,-228.49c-4.55,-25.32 -4.55,-72.01 0,-95.95c10.88,-57.57 35.02,-105.25 74.19,-146c46.29,-48.47 104.85,-78.34 168.75,-86.45c22.76,-2.78 68.85,-1 91.21,3.75Z"/>
<path android:fillColor="#FFF" android:pathData="M651.34,411.35c-3.76,1.19 -32.64,28.69 -82.5,78.54l-76.76,76.76l-53.41,-53.82c-57.17,-57.57 -57.96,-58.16 -74.19,-55.2c-7.91,1.58 -19.58,10.88 -23.94,19.19c-3.56,7.12 -3.56,20.18 0,27.1c5.14,9.5 136.11,138.48 142.24,140.06c8.51,1.98 22.35,-0.2 27.5,-4.55c2.57,-2.18 44.91,-44.51 94.37,-93.97l89.81,-90.21l-0.99,-11.87c-0.59,-9.1 -2.18,-13.65 -6.33,-18.99c-8.7,-11.46 -23.34,-16.8 -35.8,-13.04Z"/>
</vector>

View File

@ -24,6 +24,14 @@
android:background="#00FFFFFF"
/>
<clock.socoolby.com.clock.widget.textview.DigitTextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="#fff"
/>
<RelativeLayout
android:id="@+id/rel_main"
android:layout_width="match_parent"
@ -91,10 +99,11 @@
android:layout_below="@+id/tv_weather"
android:layout_marginLeft="100dp"
android:layout_marginTop="10dp"
android:src="@drawable/ic_handup" />
android:src="@drawable/ic_alarm_clock" />
<ImageButton
android:id="@+id/tv_hours_system"
android:id="@+id/tv_break"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00FFFFFF"
@ -102,8 +111,7 @@
android:layout_below="@+id/tv_weather"
android:layout_marginLeft="25dp"
android:layout_marginTop="10dp"
android:src="@drawable/ic_am"
android:visibility="gone"
android:src="@drawable/ic_handup"
/>
<ImageButton
@ -111,7 +119,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00FFFFFF"
android:layout_toRightOf="@+id/tv_hours_system"
android:layout_toRightOf="@+id/tv_break"
android:layout_below="@+id/tv_weather"
android:layout_marginLeft="40dp"
android:layout_marginTop="10dp"
@ -171,6 +179,19 @@
android:textSize="26sp" />
<ImageButton
android:id="@+id/tv_hours_system"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00FFFFFF"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="40dp"
android:layout_marginTop="10dp"
android:src="@drawable/ic_am"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -215,15 +236,6 @@
</LinearLayout>
</RelativeLayout>
<clock.socoolby.com.clock.widget.textview.DigitTextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="#fff"
/>
<clock.socoolby.com.clock.widget.animatorview.AnimatorView
android:id="@+id/tv_foreground_animatorview"
android:layout_width="match_parent"