From 2a4cf93d75f476b027c7451acdf9c63f7d67eebc Mon Sep 17 00:00:00 2001
From: zhengzhengxiaogege <2265949083@qq.com>
Date: Wed, 22 May 2019 12:36:40 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B1=95=E5=BC=80=E5=90=88?=
=?UTF-8?q?=E5=B9=B6=E3=80=81=E6=98=BE=E7=A4=BA=E6=96=87=E5=AD=97=E5=8A=9F?=
=?UTF-8?q?=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../xiaogegechen/trackview/MainActivity.java | 16 +-
app/src/main/res/layout/activity_main.xml | 19 +-
.../xiaogegechen/library/TrackView.java | 448 +++++++++++++++---
library/src/main/res/values/attrs.xml | 3 +
4 files changed, 409 insertions(+), 77 deletions(-)
diff --git a/app/src/main/java/com/github/xiaogegechen/trackview/MainActivity.java b/app/src/main/java/com/github/xiaogegechen/trackview/MainActivity.java
index 790afad..0387a21 100644
--- a/app/src/main/java/com/github/xiaogegechen/trackview/MainActivity.java
+++ b/app/src/main/java/com/github/xiaogegechen/trackview/MainActivity.java
@@ -5,7 +5,6 @@
import android.util.Log;
import android.view.View;
import android.widget.TextView;
-import android.widget.Toast;
import com.github.xiaogegechen.library.TrackView;
@@ -13,6 +12,8 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
+ private boolean state = false;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
@@ -21,6 +22,7 @@ protected void onCreate(Bundle savedInstanceState) {
final TrackView trackView = findViewById (R.id.track_view);
final TextView textView = findViewById (R.id.text_view);
+
textView.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
@@ -31,8 +33,16 @@ public void onClick(View v) {
trackView.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick(View v) {
- textView.setText ("WORLD");
- Toast.makeText (MainActivity.this, "点击了拖动按钮", Toast.LENGTH_SHORT).show ();
+
+ TrackView.Position position = trackView.getPosition ();
+ Log.d (TAG, "onClick: " + position);
+
+ if(!state){
+ trackView.close ();
+ }else{
+ trackView.open ();
+ }
+ state = !state;
}
});
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index cbe070a..74849a4 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,21 +1,24 @@
+
+ android:text="HELLO"
+ android:textSize="50sp" />
+ app:out_stroke_color="#000000"
+ app:out_stroke_width="1dp"
+ app:inner_text_size="30sp"
+ app:inner_text_color="@color/colorAccent"
+ app:inner_text="hello"/>
\ No newline at end of file
diff --git a/library/src/main/java/com/github/xiaogegechen/library/TrackView.java b/library/src/main/java/com/github/xiaogegechen/library/TrackView.java
index 6138d72..209ad51 100644
--- a/library/src/main/java/com/github/xiaogegechen/library/TrackView.java
+++ b/library/src/main/java/com/github/xiaogegechen/library/TrackView.java
@@ -1,6 +1,9 @@
package com.github.xiaogegechen.library;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -8,11 +11,14 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
+import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
/**
@@ -20,6 +26,8 @@
*/
public class TrackView extends View {
+ private static final String TAG = "TrackView";
+
// 默认大小
private static final int SIZE_DEFAULT = 50;
@@ -29,8 +37,8 @@ public class TrackView extends View {
// 松手后回到侧边的默认时长
private static final int GO_TO_BOUNDARY_INTERVAL_DEFAULT = 100;
- // 默认的外围padding
- private static final int PADDING_DEFAULT = 3;
+ // 合上的默认时长
+ private static final int CLOSE_INTERVAL_DEFAULT = 500;
// 默认控件活动边界留白
private static final int BLANK_LEFT_DEFAULT = 10;
@@ -59,18 +67,40 @@ public class TrackView extends View {
// 默认内部填充的颜色
private static final int IN_CONTENT_COLOR_DEFAULT = Color.WHITE;
- // 外部圆的画笔
+ // 默认内部文字颜色
+ private static final int IN_TEXT_COLOR_DEFAULT = Color.BLACK;
+
+ // 默认内部文字大小sp
+ private static final int IN_TEXT_SIZE_DEFAULT = 16;
+
+ // 默认内部文字
+ private static final String IN_TEXT_DEFAULT = "";
+
+ // 外部轮廓的画笔
private Paint mOutPaint;
+ // 外部轮廓的路径
+ private Path mOutPath;
+
// 内部线的画笔
private Paint mInPaint;
// 内部填涂色的画笔
private Paint mInContentPaint;
+ // 内部填涂色的路径
+ private Path mInContentPath;
+
+ // 内部文字的画笔
+ private Paint mInTextPaint;
+
// 内部的path
private Path mInPath;
+ // 左右两个半圆的外界矩形
+ private RectF mLeftRectF;
+ private RectF mRightRectF;
+
// 外部的属性
private int mOutHeight;
private int mOutWidth;
@@ -83,6 +113,9 @@ public class TrackView extends View {
private int mInnerStrokeColor;
private int mInnerStrokeWidth;
private int mInnerContentColor;
+ private int mInnerTextColor;
+ private int mInnerTextSize;
+ private String mInnerText;
// 边界属性, 单位是pixel
private int mBlankLeft;
@@ -90,10 +123,13 @@ public class TrackView extends View {
private int mBlankTop;
private int mBlankBottom;
- // 上一次的位置
+ // 上一次的触摸点的位置
private int mLastX = 0;
private int mLastY = 0;
+ // 上一次view的宽度
+ private int mLastWidth = 0;
+
// 在这个view内部,触摸位置距离view左上角的距离
private int mDisX;
private int mDisY;
@@ -107,10 +143,33 @@ public class TrackView extends View {
// 根据当前这个事件序列判定的模式
private Mode mMode = Mode.NONE;
+ // 当前的位置
+ private Position mPosition = Position.LEFT;
+
+ // 动画监听器
+ private AnimatorListenerAdapter mOpenAnimatorListenerAdapter;
+ private ValueAnimator.AnimatorUpdateListener mOpenAnimatorUpdateListener;
+ private AnimatorListenerAdapter mCloseAnimatorListenerAdapter;
+ private ValueAnimator.AnimatorUpdateListener mCloseAnimatorUpdateListener;
+
// 是否需要调整位置,因为初始的时候如果没有触摸事件,该view不受边界约束,
// 因此需要在渲染结束后进行微调,这个变量记录是否进行了微调。
private boolean mAlreadyAdjust = false;
+ // 是否正在动画
+ private boolean mIsInAnimation = false;
+
+ // 当前是否是圆形
+ private boolean mIsClosed = false;
+
+ // 是否可以执行展开和闭合的动画,针对刚开始高就大于宽的情况,
+ // 它是不应该有展开和闭合的能力的
+ private boolean mCanDoAnimation = false;
+
+ // 起始宽度和终止宽度
+ private int mOriginWidth =0;
+ private int mEndWidth =0;
+
// 屏幕像素
private int mScreenWidthInPixel;
private int mScreenHeightInPixel;
@@ -135,19 +194,25 @@ public TrackView(Context context, @Nullable AttributeSet attrs, int defStyleAttr
TypedArray ta = context.obtainStyledAttributes (attrs, R.styleable.TrackView);
// 拿到属性值
- mInnerDistance = ta.getDimensionPixelSize (R.styleable.TrackView_inner_distance, IN_DISTANCE_DEFAULT);
- mInnerLength = ta.getDimensionPixelSize (R.styleable.TrackView_inner_length, IN_LENGTH_DEFAULT);
+ mInnerDistance = ta.getDimensionPixelSize (R.styleable.TrackView_inner_distance, dp2px (IN_DISTANCE_DEFAULT));
+ mInnerLength = ta.getDimensionPixelSize (R.styleable.TrackView_inner_length, dp2px (IN_LENGTH_DEFAULT));
mInnerStrokeColor = ta.getColor (R.styleable.TrackView_inner_stroke_color, IN_STROKE_COLOR_DEFAULT);
- mInnerStrokeWidth = ta.getDimensionPixelSize (R.styleable.TrackView_inner_stroke_width, IN_STROKE_WIDTH_DEFAULT);
+ mInnerStrokeWidth = ta.getDimensionPixelSize (R.styleable.TrackView_inner_stroke_width, dp2px (IN_STROKE_WIDTH_DEFAULT));
mInnerContentColor = ta.getColor (R.styleable.TrackView_inner_content_color, IN_CONTENT_COLOR_DEFAULT);
+ mInnerTextColor = ta.getColor (R.styleable.TrackView_inner_text_color, IN_TEXT_COLOR_DEFAULT);
+ mInnerTextSize = ta.getDimensionPixelSize (R.styleable.TrackView_inner_text_size, sp2px (IN_TEXT_SIZE_DEFAULT));
+ mInnerText = ta.getString (R.styleable.TrackView_inner_text);
+ if(mInnerText == null){
+ mInnerText = IN_TEXT_DEFAULT;
+ }
mOutStrokeColor = ta.getColor (R.styleable.TrackView_out_stroke_color, OUT_STROKE_COLOR_DEFAULT);
- mOutStrokeWidth = ta.getDimensionPixelSize (R.styleable.TrackView_out_stroke_width, OUT_STROKE_WIDTH_DEFAULT);
+ mOutStrokeWidth = ta.getDimensionPixelSize (R.styleable.TrackView_out_stroke_width, dp2px (OUT_STROKE_WIDTH_DEFAULT));
- mBlankLeft = dp2px (ta.getDimensionPixelSize (R.styleable.TrackView_blank_left, BLANK_LEFT_DEFAULT));
- mBlankRight = dp2px (ta.getDimensionPixelSize (R.styleable.TrackView_blank_right, BLANK_RIGHT_DEFAULT));
- mBlankTop = dp2px (ta.getDimensionPixelSize (R.styleable.TrackView_blank_top, BLANK_TOP_DEFAULT));
- mBlankBottom = dp2px (ta.getDimensionPixelSize (R.styleable.TrackView_blank_bottom, BLANK_BOTTOM_DEFAULT));
+ mBlankLeft = ta.getDimensionPixelSize (R.styleable.TrackView_blank_left, dp2px (BLANK_LEFT_DEFAULT));
+ mBlankRight = ta.getDimensionPixelSize (R.styleable.TrackView_blank_right, dp2px (BLANK_RIGHT_DEFAULT));
+ mBlankTop = ta.getDimensionPixelSize (R.styleable.TrackView_blank_top, dp2px (BLANK_TOP_DEFAULT));
+ mBlankBottom = ta.getDimensionPixelSize (R.styleable.TrackView_blank_bottom, dp2px (BLANK_BOTTOM_DEFAULT));
// 回收typedArray
ta.recycle ();
@@ -157,54 +222,90 @@ public TrackView(Context context, @Nullable AttributeSet attrs, int defStyleAttr
@Override
protected void onDraw(Canvas canvas) {
- super.onDraw (canvas);
-
- // 外部圆的尺寸
- mOutWidth = getWidth () - getPaddingLeft () - getPaddingRight () - dp2px (PADDING_DEFAULT);
- mOutHeight = getHeight () - getPaddingBottom () -getPaddingTop () - dp2px (PADDING_DEFAULT);
-
- /**
- * * *
- * * * mInLength
- * * *
- * *
- *
- * mInDistance
- *
- * * *
- * * *
- * * *
- * *
- *
- */
- mInPath.moveTo ((float)((getWidth () / 2) - (mInnerLength / Math.sqrt (2))),
- (float)(getHeight () / 2 - (mInnerLength / Math.sqrt (2) + mInnerDistance) / 2));
-
- mInPath.lineTo ((float) getWidth () / 2,
- (float)(getHeight () / 2 - (mInnerLength / Math.sqrt (2) + mInnerDistance) / 2 + mInnerLength / Math.sqrt (2)));
-
- mInPath.lineTo ((float)((getWidth () / 2) + (mInnerLength / Math.sqrt (2))),
- (float)(getHeight () / 2 - (mInnerLength / Math.sqrt (2) + mInnerDistance) / 2));
-
- mInPath.moveTo ((float)((getWidth () / 2) - (mInnerLength / Math.sqrt (2))),
- (float)(getHeight () / 2 - (mInnerLength / Math.sqrt (2) + mInnerDistance) / 2 + mInnerDistance));
-
- mInPath.lineTo ((float) getWidth () / 2,
- (float)((float)(getHeight () / 2) - (mInnerLength / Math.sqrt (2) + mInnerDistance) / 2 + mInnerLength / Math.sqrt (2) + mInnerDistance));
-
- mInPath.lineTo ((float)((getWidth () / 2) + (mInnerLength / Math.sqrt (2))),
- (float)(getHeight () / 2 - (mInnerLength / Math.sqrt (2) + mInnerDistance) / 2 + mInnerDistance));
-
- canvas.drawCircle (getWidth () >> 1, getHeight () >> 1, Math.min (mOutWidth >> 1, mOutHeight >> 1), mOutPaint);
- canvas.drawCircle (getWidth () >> 1, getHeight () >> 1, Math.min (mOutWidth >> 1, mOutHeight >> 1), mInContentPaint);
- canvas.drawPath (mInPath, mInPaint);
+
+ // 外部形状的尺寸
+ mOutWidth = getWidth () - getPaddingLeft () - getPaddingRight ();
+ mOutHeight = getHeight () - getPaddingBottom () -getPaddingTop ();
+
+ if(mOutHeight >= mOutWidth){
+
+ // 只画圆
+ /**
+ * * *
+ * * * mInLength
+ * * *
+ * *
+ *
+ * mInDistance
+ *
+ * * *
+ * * *
+ * * *
+ * *
+ *
+ */
+ mInPath.moveTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()), (float) (mInnerLength / Math.sqrt (2)+getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)+mInnerLength*Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2));
+ mInPath.moveTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2+mInnerDistance));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()), (float) (mInnerLength / Math.sqrt (2)+getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2+mInnerDistance));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)+mInnerLength*Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2+mInnerDistance));
+
+ canvas.drawCircle (getPaddingLeft ()+mOutWidth/2, getPaddingTop ()+mOutWidth/2, mOutWidth/2, mOutPaint);
+ canvas.drawCircle (getPaddingLeft ()+mOutWidth/2, getPaddingTop ()+mOutWidth/2, mOutWidth/2, mInContentPaint);
+ canvas.drawPath (mInPath, mInPaint);
+ }else{
+ mCanDoAnimation = true;
+
+ // 拿到起始宽度和终止宽度
+ if(mOriginWidth == 0){
+ mOriginWidth = getWidth ();
+ }
+
+ if(mEndWidth == 0){
+ mEndWidth = getWidth () - (mOutWidth - mOutHeight);
+ }
+
+ mLeftRectF.set (getPaddingLeft (), getPaddingTop (), getPaddingLeft ()+mOutHeight, getPaddingTop ()+mOutHeight);
+ mRightRectF.set (getPaddingLeft ()+mOutWidth-mOutHeight, getPaddingTop (), getPaddingLeft ()+mOutWidth, getPaddingTop ()+mOutHeight);
+
+ // 整个view的填充色
+ mInContentPath.moveTo (mOutHeight/2 + getPaddingLeft ()+mOutWidth-mOutHeight, mOutHeight+getPaddingTop ());
+ mInContentPath.lineTo (mOutHeight/2+getPaddingLeft (), mOutHeight+getPaddingTop ());
+ mInContentPath.arcTo (mLeftRectF, 90, 180);
+ mInContentPath.lineTo (mOutWidth+getPaddingLeft ()-mOutHeight/2, getPaddingTop ());
+ mInContentPath.arcTo (mRightRectF, 270, 180);
+ canvas.drawPath (mInContentPath, mInContentPaint);
+
+ // 外轮廓路径
+ mOutPath.moveTo (mOutHeight/2 + getPaddingLeft ()+mOutWidth-mOutHeight, mOutHeight+getPaddingTop ());
+ mOutPath.lineTo (mOutHeight/2+getPaddingLeft (), mOutHeight+getPaddingTop ());
+ mOutPath.arcTo (mLeftRectF, 90, 180);
+ mOutPath.lineTo (mOutWidth+getPaddingLeft ()-mOutHeight/2, getPaddingTop ());
+ if(!mIsInAnimation){
+ //闭合并画出文字
+ mOutPath.arcTo (mRightRectF, 270, 180);
+ float x = mOutWidth / 2 + getPaddingLeft ();
+ float y = mOutHeight / 2 + getPaddingTop () - mInTextPaint.getFontMetrics ().top / 2 - mInTextPaint.getFontMetrics ().bottom / 2;
+ canvas.drawText (mInnerText, x,y,mInTextPaint);
+ }
+ canvas.drawPath (mOutPath, mOutPaint);
+
+ //内部图案路径
+ mInPath.moveTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()), (float) (mInnerLength / Math.sqrt (2)+getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)+mInnerLength*Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2));
+ mInPath.moveTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2+mInnerDistance));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()), (float) (mInnerLength / Math.sqrt (2)+getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2+mInnerDistance));
+ mInPath.lineTo ((float) (mOutHeight/2 + getPaddingLeft ()-mInnerLength / Math.sqrt (2)+mInnerLength*Math.sqrt (2)), (float) (getPaddingTop ()+mOutHeight/2-(mInnerDistance+mInnerLength / Math.sqrt (2))/2+mInnerDistance));
+ canvas.drawPath (mInPath, mInPaint);
+ }
// 如果需要微调的话,进行微调
if(!mAlreadyAdjust){
// 就近靠边
setTranslationX (mBlankLeft - getX ());
-
mAlreadyAdjust = true;
}
}
@@ -250,30 +351,60 @@ public boolean onTouchEvent(MotionEvent event) {
// 点击事件不需要移动
performClick ();
} else{
- if(x > mBlankLeft && x < (mScreenWidthInPixel - mBlankRight)){
+ if(x > mBlankLeft && x < (mScreenWidthInPixel - mBlankRight)
+ && mPosition != Position.LEFT
+ && mPosition != Position.RIGHT){
- // 离开点在边界之外不需要移动
+ // 离开点在边界之外不需要移动,已经在边界不需要移动
// 回到侧面
if(event.getRawX () < mScreenWidthInPixel / 2){
// 回到最左侧
-
- ObjectAnimator.ofFloat (this,
+ ObjectAnimator animator = ObjectAnimator.ofFloat (this,
"TranslationX",
getX (),
getTranslationX () + (-1 * (x - mDisX - mBlankLeft))
- ).setDuration (GO_TO_BOUNDARY_INTERVAL_DEFAULT).start ();
- x = x - (x - mDisX - mBlankLeft);
+ );
+ animator.setDuration (GO_TO_BOUNDARY_INTERVAL_DEFAULT);
+
+ // 监听动画生命周期
+ animator.addListener (new AnimatorListenerAdapter () {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPosition = Position.LEFT;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mPosition = Position.FLYING;
+ }
+ });
+ animator.start ();
+
}else{
// 回到最右侧
- ObjectAnimator.ofFloat (this,
+ ObjectAnimator animator = ObjectAnimator.ofFloat (this,
"TranslationX",
getX (),
- getTranslationX () + ((mScreenWidthInPixel - mBlankRight) - (Math.min (mOutWidth, mOutHeight) - mDisX + x))
- ).setDuration (GO_TO_BOUNDARY_INTERVAL_DEFAULT).start ();
+ getTranslationX () + ((mScreenWidthInPixel - mBlankRight) - (getWidth () - mDisX + x))
+ );
+
+ // 监听动画生命周期
+ animator.addListener (new AnimatorListenerAdapter () {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPosition = Position.RIGHT;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mPosition = Position.FLYING;
+ }
+ });
+ animator.setDuration (GO_TO_BOUNDARY_INTERVAL_DEFAULT);
+ animator.start ();
- x = x + (mScreenWidthInPixel - mBlankRight) - (Math.min (mOutWidth, mOutHeight) - mDisX + x);
}
}
}
@@ -292,7 +423,7 @@ public boolean onTouchEvent(MotionEvent event) {
// 预测量的边距
int preXLeft = x - mDisX;
- int preXRight = mScreenWidthInPixel - (x + Math.min (mOutWidth, mOutHeight) - mDisX);
+ int preXRight = mScreenWidthInPixel - (x + getWidth () - mDisX);
int preYUp = y - mDisY;
int preYDown = mScreenHeightInPixel - (y + Math.min (mOutWidth, mOutHeight) - mDisY);
@@ -300,16 +431,19 @@ public boolean onTouchEvent(MotionEvent event) {
if(preXLeft <= mBlankLeft){
// 超出左边界
+ mPosition = Position.LEFT;
dx = x - mLastX + mBlankLeft - preXLeft;
x = x + mBlankLeft - preXLeft;
}else if(preXRight <= mBlankRight){
// 超出右边界
+ mPosition = Position.RIGHT;
dx = x - mLastX - (mBlankRight - preXRight);
x = x - (mBlankRight - preXRight);
}else{
// 正常
+ mPosition = Position.FLYING;
dx = x - mLastX;
}
@@ -364,6 +498,149 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
}
}
+ // 合上
+ public void close(){
+
+ // 不能执行动画,不处理
+ if(!mCanDoAnimation){
+ return;
+ }
+
+ // 不是合上状态不处理,正在动画不处理
+ if(mIsClosed || mIsInAnimation){
+ return;
+ }
+
+ // 正在移动不处理
+ if(mPosition == Position.FLYING){
+ return;
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt (mOriginWidth, mEndWidth);
+ animator.setDuration (CLOSE_INTERVAL_DEFAULT);
+
+ // 监听动画进度
+ if (mCloseAnimatorUpdateListener == null) {
+ mCloseAnimatorUpdateListener = new ValueAnimator.AnimatorUpdateListener () {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ ViewGroup.LayoutParams params = getLayoutParams ();
+ params.height = getHeight ();
+ params.width = (Integer) animation.getAnimatedValue ();
+
+ //如果在右侧的话需要先改变位置,再改变大小
+ if(mPosition == Position.RIGHT){
+ setTranslationX (getTranslationX () + (mLastWidth - params.width));
+ mLastWidth = params.width;
+ }
+
+ // 改变view大小
+ setLayoutParams (params);
+ }
+ };
+ }
+ animator.addUpdateListener (mCloseAnimatorUpdateListener);
+
+ // 监听动画生命周期
+ if (mCloseAnimatorListenerAdapter == null) {
+ mCloseAnimatorListenerAdapter = new AnimatorListenerAdapter () {
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mLastWidth = getWidth ();
+ mIsInAnimation = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsInAnimation = false;
+ mIsClosed = true;
+
+ // 重置方便下次使用
+ mLastWidth = 0;
+ }
+ };
+ }
+ animator.addListener(mCloseAnimatorListenerAdapter);
+ animator.start ();
+ }
+
+ // 展开
+ public void open(){
+
+ // 不能执行动画,不处理
+ if(!mCanDoAnimation){
+ return;
+ }
+
+ // 不是合上状态不处理,正在动画不处理
+ if(!mIsClosed || mIsInAnimation){
+ return;
+ }
+
+ // 正在移动不处理
+ if(mPosition == Position.FLYING){
+ return;
+ }
+
+ // 监听动画进度
+ ValueAnimator animator = ValueAnimator.ofInt (mEndWidth, mOriginWidth);
+ animator.setDuration (CLOSE_INTERVAL_DEFAULT);
+ if (mOpenAnimatorUpdateListener == null) {
+ mOpenAnimatorUpdateListener = new ValueAnimator.AnimatorUpdateListener () {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ ViewGroup.LayoutParams params = getLayoutParams ();
+ params.height = getHeight ();
+ params.width = (Integer) animation.getAnimatedValue ();
+
+ //如果在右侧的话需要先改变位置,再改变大小
+ if(mPosition == Position.RIGHT){
+ setTranslationX (getTranslationX () + (mLastWidth - params.width));
+ mLastWidth = params.width;
+ }
+
+ // 改变view大小
+ setLayoutParams (params);
+ }
+ };
+ }
+ animator.addUpdateListener (mOpenAnimatorUpdateListener);
+
+ // 监听动画生命周期
+ if (mOpenAnimatorListenerAdapter == null) {
+ mOpenAnimatorListenerAdapter = new AnimatorListenerAdapter () {
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsInAnimation = true;
+ mLastWidth = getWidth ();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsInAnimation = false;
+ mIsClosed = false;
+
+ // 重置方便下次使用
+ mLastWidth = 0;
+ }
+ };
+ }
+ animator.addListener (mOpenAnimatorListenerAdapter);
+ animator.start ();
+ }
+
+ // 设置文字
+ public void setText(String text){
+ mInnerText = text;
+ invalidate ();
+ }
+
+ public Position getPosition(){
+ return mPosition;
+ }
+
/**
* 该控件的三种模式,只要触发了ACTION_MOVE就是MOVE模式
* 没有触发ACTION_MOVE但是从ACTION_DOWN开始超过了500ms就是CANCEL模式
@@ -383,6 +660,18 @@ private enum Mode{
NONE
}
+ /**
+ * view所处的位置
+ * 上下边界暂时不考虑
+ */
+ public enum Position{
+ LEFT,
+ RIGHT,
+
+ // 正在滑翔
+ FLYING
+ }
+
private void init() {
mScreenWidthInPixel = getScreenParamsInPixel ()[0];
@@ -391,18 +680,33 @@ private void init() {
mOutPaint = new Paint ();
mInPaint = new Paint ();
mInContentPaint = new Paint ();
+ mInTextPaint = new Paint ();
+
+ mOutPath = new Path ();
mInPath = new Path ();
+ mInContentPath = new Path ();
+
+ mLeftRectF = new RectF ();
+ mRightRectF = new RectF ();
mOutPaint.setStyle (Paint.Style.STROKE);
mOutPaint.setColor (mOutStrokeColor);
- mOutPaint.setStrokeWidth (dp2px(mOutStrokeWidth));
+ mOutPaint.setStrokeWidth (mOutStrokeWidth);
+ mOutPaint.setAntiAlias(true);
mInPaint.setStyle (Paint.Style.STROKE);
mInPaint.setColor (mInnerStrokeColor);
- mInPaint.setStrokeWidth(dp2px (mInnerStrokeWidth));
+ mInPaint.setStrokeWidth(mInnerStrokeWidth);
+ mInPaint.setAntiAlias(true);
mInContentPaint.setStyle (Paint.Style.FILL);
mInContentPaint.setColor (mInnerContentColor);
+
+ mInTextPaint.setTextAlign (Paint.Align.CENTER);
+ mInTextPaint.setStyle (Paint.Style.STROKE);
+ mInTextPaint.setColor (mInnerTextColor);
+ mInTextPaint.setTextSize (mInnerTextSize);
+ mInTextPaint.setAntiAlias(true);
}
/**
@@ -412,6 +716,14 @@ private static int dp2px(float dpValue) {
return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);
}
+ /**
+ * 根据手机的分辨率从 sp 的单位 转成为 px(像素)
+ */
+ private int sp2px(float spValue) {
+ final float fontScale = mContext.getResources().getDisplayMetrics().scaledDensity;
+ return (int) (spValue * fontScale + 0.5f);
+ }
+
private int[] getScreenParamsInPixel(){
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
@@ -421,4 +733,4 @@ private int[] getScreenParamsInPixel(){
return new int[]{width, height};
}
-}
+}
\ No newline at end of file
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
index 5a9b15d..1c8c42a 100644
--- a/library/src/main/res/values/attrs.xml
+++ b/library/src/main/res/values/attrs.xml
@@ -8,6 +8,9 @@
+
+
+