模仿360加速球制作一个动态ProgressBar
http://blog.csdn.net/to_be_designer/article/details/48554469
在之前一篇文章中我們講解了三種ProgressBar的做法,詳見—>《Android 自定義View——自定義ProgressBar 》。這一節中我們模仿360加速球制作一個動態ProgressBar。
當然制作之前,我們先來看看360加速球是什么樣子的:
通過上面的動圖,我們了解到360加速球是什么樣子的,現在我們開始來制作自己的ProgressBar。這里用到了之前兩篇博客的知識。大家可以參考學習:
《Android 自定義View——Path的使用 》
《Android 自定義View——自定義ProgressBar 》
《Android PorterDuff.Mode圖形混合處理 》
不廢話了,接下來進入正題……
原理解析
首先我們定義有一個Bitmap,給這個Bitmap對象定義一個Canvas畫布,我們將內容繪制在這個Bitmap上,然后再將Bitmap添加到View的Canvas上。
Bitmap的Canvas上,我們要繪制一個圓形,這個圓形代表最大進度,然后繪制圓形內的“波動的水”。這個波動的水我們要通過處理圖形混合的PorterDuff.Mode來實現。“波動的水”的實現,是通過Path中定義貝塞爾曲線完成的。我們繪制一條貝塞爾曲線,通過moveTo()和lineTo()方法,將貝塞爾曲線閉合,然后通過Handler操縱貝塞爾曲線波動。通過PorterDuff.Mode的PorterDuff.Mode.SRC_IN模式上層只顯示圓圓形重合的部分,從而實現在貝塞爾曲線在圓形內波動。
代碼實現
我們看代碼,再通過代碼解析:
<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyProgressAnimation</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">View</span> {</span><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> width;<span class="hljs-comment">//設置高</span><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> height;<span class="hljs-comment">//設置高</span><span class="hljs-keyword">private</span> Bitmap bitmap;<span class="hljs-comment">//定義Bitmap</span><span class="hljs-keyword">private</span> Canvas bitmapCanvas;<span class="hljs-comment">//定義Bitmap的畫布</span><span class="hljs-keyword">private</span> Path mPath; <span class="hljs-comment">//定義路徑</span><span class="hljs-keyword">private</span> Paint mPathPaint;<span class="hljs-comment">//定義路徑的畫筆</span><span class="hljs-keyword">private</span> Paint mPaintCircle;<span class="hljs-comment">//定義圓形的畫筆</span><span class="hljs-keyword">private</span> Paint mPaintText; <span class="hljs-comment">//定義繪制文字的畫筆</span><span class="hljs-comment">//設置進度</span><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> maxProgress = <span class="hljs-number">100</span>;<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> currentProgress = <span class="hljs-number">0</span>;<span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getMaxProgress</span>() {<span class="hljs-keyword">return</span> maxProgress;}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setMaxProgress</span>(<span class="hljs-keyword">int</span> maxProgress) {<span class="hljs-keyword">this</span>.maxProgress = maxProgress;}<span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCurrentProgress</span>() {<span class="hljs-keyword">return</span> currentProgress;}<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setCurrentProgress</span>(<span class="hljs-keyword">int</span> currentProgress) {<span class="hljs-keyword">this</span>.currentProgress = currentProgress;invalidate();<span class="hljs-comment">//實時更新進度</span>}<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> count = <span class="hljs-number">0</span>;<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> NEED_INVALIDATE = <span class="hljs-number">0X6666</span>;<span class="hljs-comment">//操作UI主線程</span><span class="hljs-keyword">private</span> Handler handler = <span class="hljs-keyword">new</span> Handler() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span>(Message msg) {<span class="hljs-keyword">super</span>.handleMessage(msg);<span class="hljs-keyword">switch</span> (msg.what) {<span class="hljs-keyword">case</span> NEED_INVALIDATE:<span class="hljs-comment">//更新時間</span>count += <span class="hljs-number">5</span>;<span class="hljs-keyword">if</span> (count > <span class="hljs-number">80</span>) {count = <span class="hljs-number">0</span>;}invalidate();sendEmptyMessageDelayed(NEED_INVALIDATE, <span class="hljs-number">50</span>);<span class="hljs-keyword">break</span>;}}};<span class="hljs-keyword">public</span> <span class="hljs-title">MyProgressAnimation</span>(Context context, AttributeSet attrs) {<span class="hljs-keyword">super</span>(context, attrs);<span class="hljs-comment">//初始化一個路徑</span>mPath = <span class="hljs-keyword">new</span> Path();<span class="hljs-comment">//初始化繪制路徑的畫筆</span>mPathPaint = <span class="hljs-keyword">new</span> Paint();mPathPaint.setAntiAlias(<span class="hljs-keyword">true</span>);mPathPaint.setColor(Color.argb(<span class="hljs-number">0xff</span>, <span class="hljs-number">0xff</span>, <span class="hljs-number">0x69</span>, <span class="hljs-number">0x5a</span>));mPathPaint.setStyle(Paint.Style.FILL);<span class="hljs-comment">//設置為填充,默認為填充,這里我們還是定義下</span>mPathPaint.setXfermode(<span class="hljs-keyword">new</span> PorterDuffXfermode(PorterDuff.Mode.SRC_IN));mPaintCircle = <span class="hljs-keyword">new</span> Paint();mPaintCircle.setAntiAlias(<span class="hljs-keyword">true</span>);mPaintCircle.setColor(Color.argb(<span class="hljs-number">0xff</span>, <span class="hljs-number">0xf8</span>, <span class="hljs-number">0x8e</span>, <span class="hljs-number">0x8b</span>));mPaintText = <span class="hljs-keyword">new</span> Paint();mPaintText.setAntiAlias(<span class="hljs-keyword">true</span>);mPaintText.setColor(Color.argb(<span class="hljs-number">0xff</span>, <span class="hljs-number">0xFF</span>, <span class="hljs-number">0xF3</span>, <span class="hljs-number">0xF7</span>));mPaintText.setTextAlign(Paint.Align.CENTER);mPaintText.setTextSize(<span class="hljs-number">50</span>);handler.sendEmptyMessageDelayed(NEED_INVALIDATE, <span class="hljs-number">50</span>);}<span class="hljs-keyword">public</span> <span class="hljs-title">MyProgressAnimation</span>(Context context) {<span class="hljs-keyword">super</span>(context);}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onMeasure</span>(<span class="hljs-keyword">int</span> widthMeasureSpec, <span class="hljs-keyword">int</span> heightMeasureSpec) {<span class="hljs-keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec);<span class="hljs-keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec);width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);setMeasuredDimension(width, height);<span class="hljs-comment">//設置寬和高</span>bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bitmapCanvas = <span class="hljs-keyword">new</span> Canvas(bitmap);}<span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onDraw</span>(Canvas canvas) {<span class="hljs-keyword">super</span>.onDraw(canvas);<span class="hljs-comment">//繪制Bitmap上的圓形</span>bitmapCanvas.drawCircle(width / <span class="hljs-number">2</span>, height / <span class="hljs-number">2</span>, <span class="hljs-number">150</span>, mPaintCircle);<span class="hljs-comment">//通過Path繪制貝塞爾曲線</span>mPath.reset();mPath.moveTo(width, (height / <span class="hljs-number">2</span> + <span class="hljs-number">150</span>) - (currentProgress * <span class="hljs-number">300</span>f / maxProgress));mPath.lineTo(width, height / <span class="hljs-number">2</span> + <span class="hljs-number">200</span>);mPath.lineTo(count, height / <span class="hljs-number">2</span> + <span class="hljs-number">200</span>);mPath.lineTo(count, (height / <span class="hljs-number">2</span> + <span class="hljs-number">150</span>) - (currentProgress * <span class="hljs-number">300</span>f / maxProgress));<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++) {mPath.rQuadTo(<span class="hljs-number">20</span>, <span class="hljs-number">5</span>, <span class="hljs-number">40</span>, <span class="hljs-number">0</span>);mPath.rQuadTo(<span class="hljs-number">20</span>, -<span class="hljs-number">5</span>, <span class="hljs-number">40</span>, <span class="hljs-number">0</span>);}mPath.close();<span class="hljs-comment">//將貝塞爾曲線繪制到Bitmap的Canvas上</span>bitmapCanvas.drawPath(mPath, mPathPaint);<span class="hljs-comment">//將Bitmap繪制到View的Canvas上</span>bitmapCanvas.drawText(currentProgress * <span class="hljs-number">100</span>f / maxProgress + <span class="hljs-string">"%"</span>, width / <span class="hljs-number">2</span>, height / <span class="hljs-number">2</span>, mPaintText);canvas.drawBitmap(bitmap, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-keyword">null</span>);} }</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li></ul>
通過這張圖片我們可以更好的理解繪制原理。
繪制紅色區域的圓形:
繪制Path軌跡區域:
注意:這里我們繪制路徑是最后使用貝塞爾曲線封閉的。然后Path封閉路徑的高度是變化的。
通過效果,只保留上層的重疊部分:
<code class="language-java hljs has-numbering"> <span class="hljs-comment">//在初始化繪制路徑的畫筆上加入這個效果</span>mPathPaint.setXfermode(<span class="hljs-keyword">new</span> PorterDuffXfermode(PorterDuff.Mode.SRC_IN));</code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li></ul>控件使用
1. 在布局中定義控件和按鈕,點擊按鈕,進度開始自動增加。
<code class="language-xml hljs has-numbering"><span class="hljs-tag"><<span class="hljs-title">LinearLayout</span> <span class="hljs-attribute">xmlns:android</span>=<span class="hljs-value">"http://schemas.android.com/apk/res/android"</span><span class="hljs-attribute">xmlns:tools</span>=<span class="hljs-value">"http://schemas.android.com/tools"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:orientation</span>=<span class="hljs-value">"vertical"</span><span class="hljs-attribute">tools:context</span>=<span class="hljs-value">"com.example.administrator.mywidgetdemo.activity.MyProgressAnimationActivity"</span>></span><span class="hljs-tag"><<span class="hljs-title">Button </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/button_start_myprogressanomation"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span> /></span><span class="hljs-tag"><<span class="hljs-title">com.example.administrator.mywidgetdemo.widget.MyProgressAnimation </span> <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/myprogressanomation"</span><span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span><span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"match_parent"</span> /></span><span class="hljs-tag"></<span class="hljs-title">LinearLayout</span>></span></code><ul style="display: block;" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul>2. Activity中點擊按鈕后增加進度。
<code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyProgressAnimationActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Activity</span> {</span><span class="hljs-keyword">private</span> Button mButton;<span class="hljs-keyword">private</span> MyProgressAnimation myprogressanomation;<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> PROGRESS= <span class="hljs-number">0X0003</span>;<span class="hljs-comment">//定義一個進度</span><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> progress;<span class="hljs-keyword">private</span> Handler handler = <span class="hljs-keyword">new</span> Handler() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span>(Message msg) {<span class="hljs-keyword">super</span>.handleMessage(msg);<span class="hljs-keyword">switch</span> (msg.what) {<span class="hljs-keyword">case</span> PROGRESS:progress++;<span class="hljs-keyword">if</span> (progress <= <span class="hljs-number">100</span>) {myprogressanomation.setCurrentProgress(progress);sendEmptyMessageDelayed(PROGRESS, <span class="hljs-number">100</span>);}<span class="hljs-keyword">break</span>;}}};<span class="hljs-annotation">@Override</span><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState) {<span class="hljs-keyword">super</span>.onCreate(savedInstanceState);setContentView(R.layout.activity_my_progress_anomation);mButton = (Button) findViewById(R.id.button_start_myprogressanomation);myprogressanomation= (MyProgressAnimation) findViewById(R.id.myprogressanomation);mButton.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {<span class="hljs-annotation">@Override</span><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span>(View v) {handler.sendEmptyMessageDelayed(PROGRESS, <span class="hljs-number">1000</span>);}});} }</code>總結
以上是生活随笔為你收集整理的模仿360加速球制作一个动态ProgressBar的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Codeforces Round#767
- 下一篇: 算法之归并排序