新西兰服务器

Android如何自定义带有圆形进度条的可长按控件功能


Android如何自定义带有圆形进度条的可长按控件功能

发布时间:2022-06-16 10:02:09 来源:高防服务器网 阅读:69 作者:iii 栏目:开发技术

今天小编给大家分享一下Android如何自定义带有圆形进度条的可长按控件功能的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

(一)继承自View并实现构造方法,代码如下:

public class LongClickView extends View {      public int DEFAULT_MAX_SECONDS = 15;      public int DEFAULT_ANNULUS_WIDTH = 5;      public int DEFAULT_ANNULUS_COLOR;      public int DEFAULT_RATE = 50;      private Paint mSmallCirclePaint;      private Paint mMiddenCirclePaint;      private Paint mBigCirclePaint;      private Paint mAngleCirclePaint;      private int mWidthSize;      private Timer mTimer;//计时器      private AtomicInteger mCount = new AtomicInteger(0);      private MyClickListener mMyClickListener;      private boolean mIsFinish = true;      private long mStartTime;//点击的时间      private long mEndTime;//点击结束的时间      private int mMaxSeconds;      private int mDelayMilliseconds;      private int mAnnulusColor;      private float mAnnulusWidth;        public interface MyClickListener {          void longClickFinish();//长按结束            void singleClickFinish();//单击结束      }        public void setMyClickListener(MyClickListener myClickListener) {          mMyClickListener = myClickListener;      }        public LongClickView(Context context) {          this(context, null);      }        public LongClickView(Context context, @Nullable AttributeSet attrs) {          this(context, attrs, 0);      }        public LongClickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)                 {          super(context, attrs, defStyleAttr);          getAttrs(context, attrs);          initView();      }  }

(二)定义并获取自定义属性,属性以及获取属性代码如下:

attr_long_click_view.xml

<?xml version="1.0" encoding="utf-8"?>  <resources>      <declare-styleable name="LongClickView">          <attr name="maxSeconds" format="integer" />          <attr name="annulusWidth" format="integer" />          <attr name="annulusColor" format="color" />          <attr name="delayMilliseconds" format="integer" />      </declare-styleable>  </resources>
 private void getAttrs(Context context, @Nullable AttributeSet attrs) {          TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LongClickView);          //maxSeconds 最大的秒数          mMaxSeconds = typedArray.getInt(R.styleable.LongClickView_maxSeconds, DEFAULT_MAX_SECONDS);          //annulusWidth 圆环的宽度          mAnnulusWidth = typedArray.getInt(R.styleable.LongClickView_annulusWidth, DEFAULT_ANNULUS_WIDTH);          //annulusColor 圆环的颜色          DEFAULT_ANNULUS_COLOR = context.getResources().getColor(R.color.color_grey);          mAnnulusColor = typedArray.getColor(R.styleable.LongClickView_annulusColor, DEFAULT_ANNULUS_COLOR);          //delayMilliseconds 进度条隔多少时间走一次,值越小走的越快,显得更流畅          mDelayMilliseconds = typedArray.getInt(R.styleable.LongClickView_delayMilliseconds, DEFAULT_RATE);      }

(三)定义画笔工具 的代码如下:

    private void initView() {          mBigCirclePaint = new Paint();          mSmallCirclePaint = new Paint();          mMiddenCirclePaint = new Paint();          mAngleCirclePaint = new Paint();          mBigCirclePaint.setStyle(Paint.Style.FILL);          mBigCirclePaint.setColor(Color.LTGRAY);          mBigCirclePaint.setAntiAlias(true);          mBigCirclePaint.setStrokeWidth(5);          mSmallCirclePaint.setStrokeWidth(5);          mSmallCirclePaint.setAntiAlias(true);          mSmallCirclePaint.setColor(Color.WHITE);          mSmallCirclePaint.setStyle(Paint.Style.FILL);            mMiddenCirclePaint.setStrokeWidth(5);          mMiddenCirclePaint.setAntiAlias(true);          mMiddenCirclePaint.setColor(Color.LTGRAY);          mMiddenCirclePaint.setStyle(Paint.Style.FILL);          mAngleCirclePaint.setStrokeWidth(5);          mAngleCirclePaint.setAntiAlias(true);          mAngleCirclePaint.setColor(mAnnulusColor);          mAngleCirclePaint.setStyle(Paint.Style.FILL);          ...//这里是长按监听        }

(四)onMeasure中测量大小,onDraw中绘制圆与扇形,代码如下:

onMeasure中,如果没有定义实际宽高就会使用父组件的宽高,如果有实际宽高便会使用自己的宽高

 @Override      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {          super.onMeasure(widthMeasureSpec, heightMeasureSpec);          mWidthSize = MeasureSpec.getSize(widthMeasureSpec);          setMeasuredDimension(mWidthSize, mWidthSize);      }

onDraw中,一共有三层圆形填充绘制以及一层扇形填充绘制,先绘制最外层的灰色圆形,再根据此时的进度绘制一定角度的扇形,然后覆盖一层灰色的圆形,最后在覆盖上一层白色的中心圆,并且在绘制过程以及绘制结束时的中心圆半径不同。代码如下:

 @Override      protected void onDraw(Canvas canvas) {          canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2, mBigCirclePaint);//最外层的填充圆          RectF rectF = new RectF(0, 0, mWidthSize, mWidthSize);//进度扇形          if (mCount.get() > 0) {              //求出每一次定时器执行所绘制的扇形度数              float perAngle = 360f / mMaxSeconds / (1000f / mDelayMilliseconds);              canvas.drawArc(rectF, 0, perAngle * mCount.get(), true, mAngleCirclePaint);          }          canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mMiddenCirclePaint);//中间一层灰色的圆          //最后绘制中心圆          if (mIsFinish) {              canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mSmallCirclePaint);          } else {              canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 8, mSmallCirclePaint);          }          super.onDraw(canvas);      }

(五)监听长按监听开始定时器并刷新画布,监听触摸事件进行结束的回调,定时器使用的是Timer类,当时间超过自定义的最大秒数时就会自动停止,并定时刷新画布,代码如下:

        this.setOnLongClickListener(new OnLongClickListener() {              @Override              public boolean onLongClick(View v) {                  mIsFinish = false;                  mCount.set(0);                  mTimer = new Timer();                  mTimer.schedule(new TimerTask() {                      @Override                      public void run() {                          mCount.addAndGet(1);                          invalidate();                          if (mCount.get() * mDelayMilliseconds >= mMaxSeconds * 1000) {                              mCount.set(0);                              this.cancel();                              invalidate();                              mIsFinish = true;                              if (mMyClickListener != null) {                                  mMyClickListener.longClickFinish();                              }                          }                      }                  }, 0, mDelayMilliseconds);                  return true;              }          });
 @Override      public boolean onTouchEvent(MotionEvent event) {          if (event.getAction() == MotionEvent.ACTION_UP) {              mEndTime = System.currentTimeMillis();              new MyAsyncTask().execute();          } else if (event.getAction() == MotionEvent.ACTION_DOWN) {              mStartTime = System.currentTimeMillis();          }          return super.onTouchEvent(event);      }

将定时器停止与停止后的判断逻辑放在AsyncTask中编写,确保定时器不会继续处理逻辑之后再做判断

    public class MyAsyncTask extends AsyncTask<Void, Void, Void> {          @Override          protected Void doInBackground(Void... voids) {              if (mTimer != null) {                  mTimer.cancel();              }              return null;          }          @Override          protected void onPostExecute(Void aVoid) {              //使用时间戳的差来判断是单击或者长按              if (mEndTime - mStartTime > 1000) {                  //防止在自动结束后松开手指又重新调用了一次长按结束的回调                  if (!mIsFinish) {                      if (mMyClickListener != null) {                          mMyClickListener.longClickFinish();                      }                  }              } else {                  //若是单击就清除进度条                  mCount.set(0);                  invalidate();                  if (mMyClickListener != null) {                      mMyClickListener.singleClickFinish();                  }              }              mIsFinish = true;          }      }

结束后的回调类代码如下:

   public interface MyClickListener {          void longClickFinish();//长按结束            void singleClickFinish();//单击结束      }

最后,完整的代码如下,自定义属性上方有贴出来代码:

public class LongClickView extends View {      public int DEFAULT_MAX_SECONDS = 15;      public int DEFAULT_ANNULUS_WIDTH = 5;      public int DEFAULT_ANNULUS_COLOR;      public int DEFAULT_RATE = 50;      private Paint mSmallCirclePaint;      private Paint mMiddenCirclePaint;      private Paint mBigCirclePaint;      private Paint mAngleCirclePaint;      private int mWidthSize;      private Timer mTimer;//计时器      private AtomicInteger mCount = new AtomicInteger(0);      private MyClickListener mMyClickListener;      private boolean mIsFinish = true;      private long mStartTime;//点击的时间      private long mEndTime;//点击结束的时间      private int mMaxSeconds;      private int mDelayMilliseconds;      private int mAnnulusColor;      private float mAnnulusWidth;      public interface MyClickListener {          void longClickFinish();//长按结束          void singleClickFinish();//单击结束      }      public void setMyClickListener(MyClickListener myClickListener) {          mMyClickListener = myClickListener;      }      public LongClickView(Context context) {          this(context, null);      }      public LongClickView(Context context, @Nullable AttributeSet attrs) {          this(context, attrs, 0);      }      public LongClickView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {          super(context, attrs, defStyleAttr);          getAttrs(context, attrs);          initView();      }      private void getAttrs(Context context, @Nullable AttributeSet attrs) {          TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LongClickView);          //maxSeconds 最大的秒数          mMaxSeconds = typedArray.getInt(R.styleable.LongClickView_maxSeconds, DEFAULT_MAX_SECONDS);          //annulusWidth 圆环的宽度          mAnnulusWidth = typedArray.getInt(R.styleable.LongClickView_annulusWidth, DEFAULT_ANNULUS_WIDTH);          //annulusColor 圆环的颜色          DEFAULT_ANNULUS_COLOR = context.getResources().getColor(R.color.color_grey);          mAnnulusColor = typedArray.getColor(R.styleable.LongClickView_annulusColor, DEFAULT_ANNULUS_COLOR);          //delayMilliseconds 进度条隔多少时间走一次,值越小走的越快,显得更流畅          mDelayMilliseconds = typedArray.getInt(R.styleable.LongClickView_delayMilliseconds, DEFAULT_RATE);      }      private static final String TAG = "LongClickView";      private void initView() {          mBigCirclePaint = new Paint();          mSmallCirclePaint = new Paint();          mMiddenCirclePaint = new Paint();          mAngleCirclePaint = new Paint();          mBigCirclePaint.setStyle(Paint.Style.FILL);          mBigCirclePaint.setColor(Color.LTGRAY);          mBigCirclePaint.setAntiAlias(true);          mBigCirclePaint.setStrokeWidth(5);          mSmallCirclePaint.setStrokeWidth(5);          mSmallCirclePaint.setAntiAlias(true);          mSmallCirclePaint.setColor(Color.WHITE);          mSmallCirclePaint.setStyle(Paint.Style.FILL);          mMiddenCirclePaint.setStrokeWidth(5);          mMiddenCirclePaint.setAntiAlias(true);          mMiddenCirclePaint.setColor(Color.LTGRAY);          mMiddenCirclePaint.setStyle(Paint.Style.FILL);          mAngleCirclePaint.setStrokeWidth(5);          mAngleCirclePaint.setAntiAlias(true);          mAngleCirclePaint.setColor(mAnnulusColor);          mAngleCirclePaint.setStyle(Paint.Style.FILL);          this.setOnLongClickListener(new OnLongClickListener() {              @Override              public boolean onLongClick(View v) {                  mIsFinish = false;                  mCount.set(0);                  mTimer = new Timer();                  mTimer.schedule(new TimerTask() {                      @Override                      public void run() {                          mCount.addAndGet(1);                          invalidate();                          if (mCount.get() * mDelayMilliseconds >= mMaxSeconds * 1000) {                              mCount.set(0);                              this.cancel();                              invalidate();                              mIsFinish = true;                              if (mMyClickListener != null) {                                  mMyClickListener.longClickFinish();                              }                          }                      }                  }, 0, mDelayMilliseconds);                  return true;              }          });      }      @Override      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {          super.onMeasure(widthMeasureSpec, heightMeasureSpec);          mWidthSize = MeasureSpec.getSize(widthMeasureSpec);          setMeasuredDimension(mWidthSize, mWidthSize);      }      @Override      protected void onDraw(Canvas canvas) {          canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2, mBigCirclePaint);//最外层的填充圆          RectF rectF = new RectF(0, 0, mWidthSize, mWidthSize);//进度扇形          if (mCount.get() > 0) {              //求出每一次定时器执行所绘制的扇形度数              float perAngle = 360f / mMaxSeconds / (1000f / mDelayMilliseconds);              canvas.drawArc(rectF, 0, perAngle * mCount.get(), true, mAngleCirclePaint);          }          canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mMiddenCirclePaint);//中间一层灰色的圆          //最后绘制中心圆          if (mIsFinish) {              canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 2 - mAnnulusWidth, mSmallCirclePaint);          } else {              canvas.drawCircle(mWidthSize / 2, mWidthSize / 2, mWidthSize / 8, mSmallCirclePaint);          }          super.onDraw(canvas);      }      @Override      public boolean onTouchEvent(MotionEvent event) {          if (event.getAction() == MotionEvent.ACTION_UP) {              mEndTime = System.currentTimeMillis();              new MyAsyncTask().execute();          } else if (event.getAction() == MotionEvent.ACTION_DOWN) {              mStartTime = System.currentTimeMillis();          }          return super.onTouchEvent(event);      }      public class MyAsyncTask extends AsyncTask<Void, Void, Void> {          @Override          protected Void doInBackground(Void... voids) {              if (mTimer != null) {                  mTimer.cancel();              }              return null;          }          @Override          protected void onPostExecute(Void aVoid) {              //使用时间戳的差来判断是单击或者长按              if (mEndTime - mStartTime > 1000) {                  //防止在结束后松开手指有重新调用了一次长按结束的回调                  if (!mIsFinish) {                      if (mMyClickListener != null) {                          mMyClickListener.longClickFinish();                      }                  }              } else {                  mCount.set(0);                  invalidate();                  if (mMyClickListener != null) {                      mMyClickListener.singleClickFinish();                  }              }              mIsFinish = true;          }      }  }

使用的代码如下:

activity_long_click_view.xml

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:gravity="center"      android:orientation="vertical">        <com.example.customerview.long_click_view.LongClickView          android:id="@+id/long_click_view"          android:layout_width="100dp"          android:layout_height="wrap_content"          app:annulusColor="@color/color_2196F3"          app:annulusWidth="20"          app:delayMilliseconds="40"          app:maxSeconds="4" />        <TextView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_marginTop="20dp"          android:text="长按录制视频,单击拍照"          android:textColor="@color/colorBlack"          android:textSize="20dp" />  </LinearLayout>

LongClickViewActivity.java

        mLongClickView.setMyClickListener(new LongClickView.MyClickListener() {              @Override              public void longClickFinish() {                  runOnUiThread(new Runnable() {                      @Override                      public void run() {                          Toast.makeText(LongClickViewActivity.this, "长按结束", Toast.LENGTH_SHORT).show();                      }                  });              }                @Override              public void singleClickFinish() {                  runOnUiThread(new Runnable() {                      @Override                      public void run() {                          Toast.makeText(LongClickViewActivity.this, "单击结束", Toast.LENGTH_SHORT).show();                      }                  });              }          });

以上就是“Android如何自定义带有圆形进度条的可长按控件功能”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注高防服务器网行业资讯频道。

[微信提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

[图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]
[