Android特效专辑(十一)——仿水波纹流球进度条控制器,实现高端大气的主流特效


今天看到一个效果挺不错的,就模仿了下来,加上了一些自己想要的效果,感觉还不错的样子,所以就分享出来了,话不多说,上图

截图

CircleView

这里主要是实现中心圆以及水波特效

  1. package com.lgl.circleview;
  2. import android.content.Context;
  3. import android.graphics.Canvas;
  4. import android.graphics.Color;
  5. import android.graphics.Paint;
  6. import android.graphics.Path;
  7. import android.graphics.RectF;
  8. import android.os.Handler;
  9. import android.os.Parcel;
  10. import android.os.Parcelable;
  11. import android.util.AttributeSet;
  12. import android.view.View;
  13. import android.widget.ProgressBar;
  14. /**
  15. * 水波圆
  16. *
  17. * @author lgl
  18. *
  19. */
  20. public class CircleView extends View {
  21. private Context mContext;
  22. private int mScreenWidth;
  23. private int mScreenHeight;
  24. private Paint mRingPaint;
  25. private Paint mCirclePaint;
  26. private Paint mWavePaint;
  27. private Paint linePaint;
  28. private Paint flowPaint;
  29. private Paint leftPaint;
  30. private int mRingSTROKEWidth = 15;
  31. private int mCircleSTROKEWidth = 2;
  32. private int mLineSTROKEWidth = 1;
  33. private int mCircleColor = Color.WHITE;
  34. private int mRingColor = Color.WHITE;
  35. private int mWaveColor = Color.WHITE;
  36. private Handler mHandler;
  37. private long c = 0L;
  38. private boolean mStarted = false;
  39. private final float f = 0.033F;
  40. private int mAlpha = 50;// 透明度
  41. private float mAmplitude = 10.0F; // 振幅
  42. private float mWaterLevel = 0.5F;// 水高(0~1)
  43. private Path mPath;
  44. // 绘制文字显示在圆形中间,只是我没有设置,我觉得写在布局上也挺好的
  45. private String flowNum = "";
  46. private String flowLeft = "还剩余";
  47. /**
  48. * @param context
  49. */
  50. public CircleView(Context context) {
  51. super(context);
  52. // TODO Auto-generated constructor stub
  53. mContext = context;
  54. init(mContext);
  55. }
  56. /**
  57. * @param context
  58. * @param attrs
  59. */
  60. public CircleView(Context context, AttributeSet attrs) {
  61. super(context, attrs);
  62. // TODO Auto-generated constructor stub
  63. mContext = context;
  64. init(mContext);
  65. }
  66. /**
  67. * @param context
  68. * @param attrs
  69. * @param defStyleAttr
  70. */
  71. public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
  72. super(context, attrs, defStyleAttr);
  73. // TODO Auto-generated constructor stub
  74. mContext = context;
  75. init(mContext);
  76. }
  77. public void setmWaterLevel(float mWaterLevel) {
  78. this.mWaterLevel = mWaterLevel;
  79. }
  80. private void init(Context context) {
  81. mRingPaint = new Paint();
  82. mRingPaint.setColor(mRingColor);
  83. mRingPaint.setAlpha(50);
  84. mRingPaint.setStyle(Paint.Style.STROKE);
  85. mRingPaint.setAntiAlias(true);
  86. mRingPaint.setStrokeWidth(mRingSTROKEWidth);
  87. mCirclePaint = new Paint();
  88. mCirclePaint.setColor(mCircleColor);
  89. mCirclePaint.setStyle(Paint.Style.STROKE);
  90. mCirclePaint.setAntiAlias(true);
  91. mCirclePaint.setStrokeWidth(mCircleSTROKEWidth);
  92. linePaint = new Paint();
  93. linePaint.setColor(mCircleColor);
  94. linePaint.setStyle(Paint.Style.STROKE);
  95. linePaint.setAntiAlias(true);
  96. linePaint.setStrokeWidth(mLineSTROKEWidth);
  97. flowPaint = new Paint();
  98. flowPaint.setColor(mCircleColor);
  99. flowPaint.setStyle(Paint.Style.FILL);
  100. flowPaint.setAntiAlias(true);
  101. flowPaint.setTextSize(36);
  102. leftPaint = new Paint();
  103. leftPaint.setColor(mCircleColor);
  104. leftPaint.setStyle(Paint.Style.FILL);
  105. leftPaint.setAntiAlias(true);
  106. leftPaint.setTextSize(36);
  107. mWavePaint = new Paint();
  108. mWavePaint.setStrokeWidth(1.0F);
  109. mWavePaint.setColor(mWaveColor);
  110. mWavePaint.setAlpha(mAlpha);
  111. mPath = new Path();
  112. mHandler = new Handler() {
  113. @Override
  114. public void handleMessage(android.os.Message msg) {
  115. if (msg.what == 0) {
  116. invalidate();
  117. if (mStarted) {
  118. // 不断发消息给自己,使自己不断被重绘
  119. mHandler.sendEmptyMessageDelayed(0, 60L);
  120. }
  121. }
  122. }
  123. };
  124. }
  125. @Override
  126. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  127. int width = measure(widthMeasureSpec, true);
  128. int height = measure(heightMeasureSpec, false);
  129. if (width < height) {
  130. setMeasuredDimension(width, width);
  131. } else {
  132. setMeasuredDimension(height, height);
  133. }
  134. }
  135. /**
  136. * @category 测量
  137. * @param measureSpec
  138. * @param isWidth
  139. * @return
  140. */
  141. private int measure(int measureSpec, boolean isWidth) {
  142. int result;
  143. int mode = MeasureSpec.getMode(measureSpec);
  144. int size = MeasureSpec.getSize(measureSpec);
  145. int padding = isWidth ? getPaddingLeft() + getPaddingRight()
  146. : getPaddingTop() + getPaddingBottom();
  147. if (mode == MeasureSpec.EXACTLY) {
  148. result = size;
  149. } else {
  150. result = isWidth ? getSuggestedMinimumWidth()
  151. : getSuggestedMinimumHeight();
  152. result += padding;
  153. if (mode == MeasureSpec.AT_MOST) {
  154. if (isWidth) {
  155. result = Math.max(result, size);
  156. } else {
  157. result = Math.min(result, size);
  158. }
  159. }
  160. }
  161. return result;
  162. }
  163. @Override
  164. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  165. // TODO Auto-generated method stub
  166. super.onSizeChanged(w, h, oldw, oldh);
  167. mScreenWidth = w;
  168. mScreenHeight = h;
  169. }
  170. @Override
  171. protected void onDraw(Canvas canvas) {
  172. // TODO Auto-generated method stub
  173. super.onDraw(canvas);
  174. // 得到控件的宽高
  175. int width = getWidth();
  176. int height = getHeight();
  177. setBackgroundColor(mContext.getResources().getColor(R.color.main_bg));
  178. // 计算当前油量线和水平中线的距离
  179. float centerOffset = Math.abs(mScreenWidth / 2 * mWaterLevel
  180. - mScreenWidth / 4);
  181. // 计算油量线和与水平中线的角度
  182. float horiAngle = (float) (Math.asin(centerOffset / (mScreenWidth / 4)) * 180 / Math.PI);
  183. // 扇形的起始角度和扫过角度
  184. float startAngle, sweepAngle;
  185. if (mWaterLevel > 0.5F) {
  186. startAngle = 360F - horiAngle;
  187. sweepAngle = 180F + 2 * horiAngle;
  188. } else {
  189. startAngle = horiAngle;
  190. sweepAngle = 180F - 2 * horiAngle;
  191. }
  192. canvas.drawLine(mScreenWidth * 3 / 8, mScreenHeight * 5 / 8,
  193. mScreenWidth * 5 / 8, mScreenHeight * 5 / 8, linePaint);
  194. float num = flowPaint.measureText(flowNum);
  195. canvas.drawText(flowNum, mScreenWidth * 4 / 8 - num / 2,
  196. mScreenHeight * 4 / 8, flowPaint);
  197. float left = leftPaint.measureText(flowLeft);
  198. canvas.drawText(flowLeft, mScreenWidth * 4 / 8 - left / 2,
  199. mScreenHeight * 3 / 8, leftPaint);
  200. // 如果未开始(未调用startWave方法),绘制一个扇形
  201. if ((!mStarted) || (mScreenWidth == 0) || (mScreenHeight == 0)) {
  202. // 绘制,即水面静止时的高度
  203. RectF oval = new RectF(mScreenWidth / 4, mScreenHeight / 4,
  204. mScreenWidth * 3 / 4, mScreenHeight * 3 / 4);
  205. canvas.drawArc(oval, startAngle, sweepAngle, false, mWavePaint);
  206. return;
  207. }
  208. // 绘制,即水面静止时的高度
  209. // 绘制,即水面静止时的高度
  210. RectF oval = new RectF(mScreenWidth / 4, mScreenHeight / 4,
  211. mScreenWidth * 3 / 4, mScreenHeight * 3 / 4);
  212. canvas.drawArc(oval, startAngle, sweepAngle, false, mWavePaint);
  213. if (this.c >= 8388607L) {
  214. this.c = 0L;
  215. }
  216. // 每次onDraw时c都会自增
  217. c = (1L + c);
  218. float f1 = mScreenHeight * (1.0F - (0.25F + mWaterLevel / 2))
  219. - mAmplitude;
  220. // 当前油量线的长度
  221. float waveWidth = (float) Math.sqrt(mScreenWidth * mScreenWidth / 16
  222. - centerOffset * centerOffset);
  223. // 与圆半径的偏移量
  224. float offsetWidth = mScreenWidth / 4 - waveWidth;
  225. int top = (int) (f1 + mAmplitude);
  226. mPath.reset();
  227. // 起始振动X坐标,结束振动X坐标
  228. int startX, endX;
  229. if (mWaterLevel > 0.50F) {
  230. startX = (int) (mScreenWidth / 4 + offsetWidth);
  231. endX = (int) (mScreenWidth / 2 + mScreenWidth / 4 - offsetWidth);
  232. } else {
  233. startX = (int) (mScreenWidth / 4 + offsetWidth - mAmplitude);
  234. endX = (int) (mScreenWidth / 2 + mScreenWidth / 4 - offsetWidth + mAmplitude);
  235. }
  236. // 波浪效果
  237. while (startX < endX) {
  238. int startY = (int) (f1 - mAmplitude
  239. * Math.sin(Math.PI
  240. * (2.0F * (startX + this.c * width * this.f))
  241. / width));
  242. canvas.drawLine(startX, startY, startX, top, mWavePaint);
  243. startX++;
  244. }
  245. canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2, mScreenWidth / 4
  246. + mRingSTROKEWidth / 2, mRingPaint);
  247. canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2,
  248. mScreenWidth / 4, mCirclePaint);
  249. canvas.restore();
  250. }
  251. @Override
  252. public Parcelable onSaveInstanceState() {
  253. Parcelable superState = super.onSaveInstanceState();
  254. SavedState ss = new SavedState(superState);
  255. ss.progress = (int) c;
  256. return ss;
  257. }
  258. @Override
  259. public void onRestoreInstanceState(Parcelable state) {
  260. SavedState ss = (SavedState) state;
  261. super.onRestoreInstanceState(ss.getSuperState());
  262. c = ss.progress;
  263. }
  264. @Override
  265. protected void onAttachedToWindow() {
  266. super.onAttachedToWindow();
  267. // 关闭硬件加速,防止异常unsupported operation exception
  268. this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
  269. }
  270. @Override
  271. protected void onDetachedFromWindow() {
  272. super.onDetachedFromWindow();
  273. }
  274. /**
  275. * @category 开始波动
  276. */
  277. public void startWave() {
  278. if (!mStarted) {
  279. this.c = 0L;
  280. mStarted = true;
  281. this.mHandler.sendEmptyMessage(0);
  282. }
  283. }
  284. /**
  285. * @category 停止波动
  286. */
  287. public void stopWave() {
  288. if (mStarted) {
  289. this.c = 0L;
  290. mStarted = false;
  291. this.mHandler.removeMessages(0);
  292. }
  293. }
  294. /**
  295. * @category 保存状态
  296. */
  297. static class SavedState extends BaseSavedState {
  298. int progress;
  299. /**
  300. * Constructor called from {@link ProgressBar#onSaveInstanceState()}
  301. */
  302. SavedState(Parcelable superState) {
  303. super(superState);
  304. }
  305. /**
  306. * Constructor called from {@link #CREATOR}
  307. */
  308. private SavedState(Parcel in) {
  309. super(in);
  310. progress = in.readInt();
  311. }
  312. @Override
  313. public void writeToParcel(Parcel out, int flags) {
  314. super.writeToParcel(out, flags);
  315. out.writeInt(progress);
  316. }
  317. public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
  318. public SavedState createFromParcel(Parcel in) {
  319. return new SavedState(in);
  320. }
  321. public SavedState[] newArray(int size) {
  322. return new SavedState[size];
  323. }
  324. };
  325. }
  326. }

我们运行一下

其实他是十分的空旷的,所以也值得我们去定制,我们在中间加个流量显示,再加个进度条

activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. android:background="@color/main_bg" >
  7. <TextView
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_alignParentTop="true"
  11. android:layout_centerHorizontal="true"
  12. android:layout_marginTop="10dp"
  13. android:text="流量"
  14. android:textColor="@android:color/white"
  15. android:textSize="18sp" />
  16. <com.lgl.circleview.CircleView
  17. android:id="@+id/wave_view"
  18. android:layout_width="fill_parent"
  19. android:layout_height="fill_parent"
  20. android:layout_centerInParent="true" />
  21. <TextView
  22. android:id="@+id/power"
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:layout_centerInParent="true"
  26. android:textColor="@android:color/white" />
  27. <SeekBar
  28. android:id="@+id/seekBar"
  29. android:layout_width="match_parent"
  30. android:layout_height="wrap_content"
  31. android:layout_alignParentBottom="true"
  32. android:layout_marginBottom="150dp" />
  33. </RelativeLayout>

我们要实现这个,就要调用它的初始化以及start方法

  1. mCircleView = (CircleView) findViewById(R.id.wave_view);
  2. // 设置多高,float,0.1-1F
  3. mCircleView.setmWaterLevel(0.1F);
  4. // 开始执行
  5. mCircleView.startWave();

别忘了activity销毁的时候把它回收哦

  1. @Override
  2. protected void onDestroy() {
  3. // TODO Auto-generated method stub
  4. mCircleView.stopWave();
  5. mCircleView = null;
  6. super.onDestroy();
  7. }

我们再运行一遍

但是我们要怎么让水波纹随着进度条一起上升下降尼?,这里我们就要用到我们刚才写的SeekBar了,我们实现它的setOnSeekBarChangeListener来监听,这样我们就要复写他的三个方法,这里我们只要用到一个

  1. public void onProgressChanged(SeekBar seekBar, int progress,
  2. boolean fromUser) {
  3. //跟随进度条滚动
  4. mCircleView.setmWaterLevel((float) progress / 100);
  5. }

这里,我们要这样算的,我们设置高度的单位是float,也就是从0-1F,而我们的进度是int progress,从0-100,我们就要用(float) progress / 100)并且强转来得到单位,好了,我们现在水波纹的高度就是随着我们的进度条一起变化了,我们再来运行一下

好的,这样的话,我们就只剩下一个了,就是让大小随着我们的进度条变化了,这里我们因为更新UI不能再主线程中操作,所以我们需要用到我们的老伙计Handler了,但是用到handler还不够,我们的进度条数值也是在内部类里面,所以这里我们需要用到Handler来传值了,这里我们用的是Bundle,我们还是在onProgressChanged方法中操作了

  1. //创建一个消息
  2. Message message = new Message();
  3. Bundle bundle = new Bundle();
  4. //put一个int值
  5. bundle.putInt("progress", progress);
  6. //装载
  7. message.setData(bundle);
  8. //发送消息
  9. handler.sendMessage(message);
  10. //创建表示
  11. message.what = 1;

消息发送过去了,我们就在前面写个Handler去接收就是了

  1. private Handler handler = new Handler() {
  2. public void handleMessage(android.os.Message msg) {
  3. if (msg.what == 1) {
  4. int num = msg.getData().getInt("progress");
  5. Log.i("num", num + "");
  6. power.setText((float) num / 100 * max + "M/" + max + "M");
  7. }
  8. }
  9. };

这里的计算公式尼,是当前的数值/100得到百分比再去*最大值。我们现在可以完整的运行一下了,其实和最上面运行的图片是一样的

MainActivity

  1. package com.lgl.circleview;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.os.Handler;
  5. import android.os.Message;
  6. import android.util.Log;
  7. import android.widget.SeekBar;
  8. import android.widget.TextView;
  9. public class MainActivity extends Activity {
  10. private CircleView mCircleView;
  11. private SeekBar mSeekBar;
  12. private TextView power;
  13. private int max = 1024;
  14. private int min = 102;
  15. private Handler handler = new Handler() {
  16. public void handleMessage(android.os.Message msg) {
  17. if (msg.what == 1) {
  18. int num = msg.getData().getInt("progress");
  19. Log.i("num", num + "");
  20. power.setText((float) num / 100 * max + "M/" + max + "M");
  21. }
  22. }
  23. };
  24. @Override
  25. protected void onCreate(Bundle savedInstanceState) {
  26. super.onCreate(savedInstanceState);
  27. getActionBar().hide();
  28. setContentView(R.layout.activity_main);
  29. power = (TextView) findViewById(R.id.power);
  30. power.setText(min + "M/" + max + "M");
  31. mCircleView = (CircleView) findViewById(R.id.wave_view);
  32. // 设置多高,float,0.1-1F
  33. mCircleView.setmWaterLevel(0.1F);
  34. // 开始执行
  35. mCircleView.startWave();
  36. mSeekBar = (SeekBar) findViewById(R.id.seekBar);
  37. mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
  38. @Override
  39. public void onProgressChanged(SeekBar seekBar, int progress,
  40. boolean fromUser) {
  41. mCircleView.setmWaterLevel((float) progress / 100);
  42. // 创建一个消息
  43. Message message = new Message();
  44. Bundle bundle = new Bundle();
  45. // put一个int值
  46. bundle.putInt("progress", progress);
  47. // 装载
  48. message.setData(bundle);
  49. // 发送消息
  50. handler.sendMessage(message);
  51. // 创建表示
  52. message.what = 1;
  53. }
  54. @Override
  55. public void onStartTrackingTouch(SeekBar seekBar) {
  56. }
  57. @Override
  58. public void onStopTrackingTouch(SeekBar seekBar) {
  59. }
  60. });
  61. }
  62. @Override
  63. protected void onDestroy() {
  64. // TODO Auto-generated method stub
  65. mCircleView.stopWave();
  66. mCircleView = null;
  67. super.onDestroy();
  68. }
  69. }

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9435934

Android特效专辑(十一)——仿水波纹流量球进度条控制器,实现高端大气的主流特效的更多相关文章

  1. Android -- 真正的 高仿微信 打开网页的进度条效果

    (本博客为原创,http://www.cnblogs.com/linguanh/) 目录: 一,为什么说是真正的高仿? 二,为什么要搞缓慢效果? 三,我的实现思路 四,代码,内含注释 五,使用方法与截 ...

  2. Android中通过线程实现更新ProgressDialog(对话进度条)

    作为开发者我们需要经常站在用户角度考虑问题,比如在应用商城下载软件时,当用户点击下载按钮,则会有下载进度提示页面出现,现在我们通过线程休眠的方式模拟下载进度更新的演示,如图(这里为了截图方便设置对话进 ...

  3. Android UI系列-----时间、日期、Toasts和进度条Dialog

    您可以通过点击 右下角 的按钮 来对文章内容作出评价, 也可以通过左下方的 关注按钮 来关注我的博客的最新动态. 如果文章内容对您有帮助, 不要忘记点击右下角的 推荐按钮 来支持一下哦 如果您对文章内 ...

  4. 【转】Android UI系列-----时间、日期、Toasts和进度条Dialog

    原文网址:http://www.cnblogs.com/xiaoluo501395377/p/3421727.html 您可以通过点击 右下角 的按钮 来对文章内容作出评价, 也可以通过左下方的 关注 ...

  5. Android简易实战教程--第二话《两种进度条》

    点击按钮模拟进度条下载进度,"下载"完成进度条消失. 代码如下: xml: <?xml version="1.0" encoding="utf- ...

  6. 阅读《Android 从入门到精通》(17)——进度条

    进度条(ProgressBar) java.lang.Object; android.view.View; android.widget.ProgressBar; ProgressBar 类方法 Pr ...

  7. 仿MIUI音量变化环形进度条实现

    Android中使用环形进度条的业务场景事实上蛮多的,比方下载文件的时候使用环形进度条.会给用户眼前一亮的感觉:再比方我大爱的MIUI系统,它的音量进度条就是使用环形进度条,尽显小米"为发烧 ...

  8. Android 自定义View—清爽小巧灵活的多节点进度条

    前言 最近项目有一个节点进度条的小需求,完成后,想分享出来希望可以帮到有需要的同学. 真机效果图 自定义View完整代码 开箱即用~,注释已经炒鸡详细了 /** * @description: 节点进 ...

  9. Android 自定义 View 圆形进度条总结

    Android 自定义圆形进度条总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 微信公众号:牙锅子 源码:CircleProgress 文中如有纰漏,欢迎大家留言指出. 最近 ...

随机推荐

  1. Not saving crash log because we have reached the limit for logs to store on disk.解决办法

    一.问题简述: Xcode, window>Devices>DEVICES选中自已的设备,打开控制台:提示日志存量已达限制,这个是系统抛出的log."Not saving cra ...

  2. activiti实战系列 activiti连线

    11:连线 11.1:流程图 注意:如果将流程图放置在和java类相同的路径,需要配置: 11.2:部署流程定义+启动流程实例 11.3:查询我的个人任务 11.4:完成任务 说明: 1)使用流程变量 ...

  3. JAVA面向对象-----接口的概述

    接口的概述 **接口(interface):**usb接口,主要是使用来拓展笔记本的功能,那么在java中的接口主要是使用来拓展定义类的功能,可以弥补java中单继承的缺点. class Pencil ...

  4. 携程React Native实践

    React Native(下文简称 RN)开源已经一年多时间,国内各大互联网公司都在使用,携程也在今年 5 月份投入资源开始引入,并推广给多个业务团队使用,本文将会分享我们遇到的一些问题以及我们的优化 ...

  5. HDU2612---(两次BFS)

    Description Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Nin ...

  6. 学习笔记3-开发与运行(卸载)第一个ANDROID应用

    新建Android项目 1.      配置好Android坏境以后,新建项目选择Android Project. 2.      选择针对哪个平台开发的应用(Android2/Android4等) ...

  7. 深入分析Spring混合事务

    在ORM框架的事务管理器的事务内,使用JdbcTemplate执行SQL是不会纳入事务管理的. 下面进行源码分析,看为什么必须要在DataSourceTransactionManager的事务内使用J ...

  8. Java 8新特性探究(二)类型注解和重复注解

    本文将介绍java 8的第二个特性:类型注解. 注解大家都知道,从java5开始加入这一特性,发展到现在已然是遍地开花,在很多框架中得到了广泛的使用,用来简化程序中的配置.那充满争议的类型注解究竟是什 ...

  9. ios swift模仿qq登陆界面,xml布局

    给大家推荐两个学习的地址: 极客学院的视频:http://www.jikexueyuan.com/path/ios/ 一个博客:http://blog.csdn.net/lizhongfu2013/a ...

  10. javascript之自定义数组工具对象

    <pre name="code" class="html">/* 需求:编写一个js文件,在js文件中自定义一个数组工具对象, 该工具对象要有一个找 ...