開源項目學習與分析系列——ArcMenu

<p>&#160;&#160;&#160; 從如今開始,我將寫下因爲項目而接觸到的優秀的Android開源項目的學習理解。一來有助於本身的提升,方便之後的查閱;二來學習Android須要有開源的精神,和別人分享是很重要的。我如今對Android應用開發的理解還不深,但願能在這個過程當中,迅速的成長起來。</p> <p>&#160;&#160;&#160; 廢話很少說,先展現一下,ArcMenu &amp; RayMenu的效果圖:</p> <p><a href="http://static.oschina.net/uploads/img/201404/03190616_jOqI.png"><img title="preview1" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="preview1" src="http://static.oschina.net/uploads/img/201404/03190616_wDnb.png" width="229" height="206" /></a> <a href="http://static.oschina.net/uploads/img/201404/03190616_RAOV.png"><img title="68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f752f31313336393638372f70726576696577302e706e67" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="68747470733a2f2f646c2e64726f70626f7875736572636f6e74656e742e636f6d2f752f31313336393638372f70726576696577302e706e67" src="http://static.oschina.net/uploads/img/201404/03190616_p9mK.png" width="244" height="205" /></a> <a href="http://static.oschina.net/uploads/img/201404/03190617_Whoe.png"><img title="raymenu" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="raymenu" src="http://static.oschina.net/uploads/img/201404/03190617_jPpi.png" width="244" height="52" /></a> </p> <h3>RayMenu機制詳解:</h3> <p>&#160;&#160;&#160;&#160;&#160;&#160; 其涉及的知識,是ViewGroup的佈局與Android動畫。因爲ArcMenu &amp; RayMenu實質上是同樣的,只是ArcMenu佈局計算上稍顯複復雜一些,故選擇其RayMenu做爲例子來說,柿子仍是得撿軟的捏呀。</p> <p>&#160;&#160;&#160;&#160;&#160; RayMenu的用到的幾個文件以下:</p> <p>&#160;&#160;&#160;&#160;&#160; <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/src/com/capricorn/RayLayout.java">RayLayout.java</a>——用於控制彈出菜單的動畫與佈局</p> <p>&#160;&#160;&#160;&#160;&#160; <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/src/com/capricorn/RayMenu.java">RayMenu.java</a>——用於控制控件的邏輯,好比按下紅色按鈕後,彈出菜單等。</p> <p>&#160;&#160;&#160;&#160;&#160; <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/src/com/capricorn/RotateAndTranslateAnimation.java">RotateAndTranslateAnimation.java</a>——這只是個動畫</p> <p>&#160;&#160;&#160;&#160;&#160; <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/res/layout/ray_menu.xml">ray_menu.xml</a>——rayMenu的佈局文件</p> <p></p> <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 關於它的使用方法,很簡單,見<a href="https://github.com/daCapricorn/ArcMenu/blob/master/sample/src/com/capricorn/example/MainActivity.java">MainActivity.java</a>。</p> <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 下面,我就從咱們使用的流程開始說,</p> <div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span>setContentView(R.layout.main);</pre>css

</div> <style type="text/css">html

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>java

<p></p>android

<h3>實例化:</h3>git

<p>使用setContentView(int)會解析xml生成真正的view類,在這個過程RayMenu被實例化了,咱們看一下實例化過程的初始化的代碼。</p>github

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">class</span> RayMenu extends RelativeLayout {</pre>canvas

<pre><span class="lnum">   2:  </span>    <span class="kwrd">private</span> RayLayout mRayLayout;</pre>

<pre class="alt"><span class="lnum">   3:  </span>&#160;</pre>

<pre><span class="lnum">   4:  </span>    <span class="kwrd">private</span> ImageView mHintView;</pre>

<pre class="alt"><span class="lnum">   5:  </span>&#160;</pre>

<pre><span class="lnum">   6:  </span>    <span class="kwrd">public</span> RayMenu(Context context) {</pre>

<pre class="alt"><span class="lnum">   7:  </span>        super(context);</pre>

<pre><span class="lnum">   8:  </span>        init(context);</pre>

<pre class="alt"><span class="lnum">   9:  </span>    }</pre>

<pre><span class="lnum">  10:  </span>&#160;</pre>

<pre class="alt"><span class="lnum">  11:  </span>    <span class="kwrd">public</span> RayMenu(Context context, AttributeSet attrs) {</pre>

<pre><span class="lnum">  12:  </span>        super(context, attrs);</pre>

<pre class="alt"><span class="lnum">  13:  </span>        init(context);</pre>

<pre><span class="lnum">  14:  </span>    }</pre>

<pre class="alt"><span class="lnum">  15:  </span>&#160;</pre>

<pre><span class="lnum">  16:  </span>    <span class="kwrd">private</span> <span class="kwrd">void</span> init(Context context) {</pre>

<pre class="alt"><span class="lnum">  17:  </span>        setLayoutParams(<span class="kwrd">new</span> LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));</pre>

<pre><span class="lnum">  18:  </span>        setClipChildren(<span class="kwrd">false</span>);</pre>

<pre class="alt"><span class="lnum">  19:  </span>&#160;</pre>

<pre><span class="lnum">  20:  </span>        LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);</pre>

<pre class="alt"><span class="lnum">  21:  </span>        li.inflate(R.layout.ray_menu, <span class="kwrd">this</span>);</pre>

<pre><span class="lnum">  22:  </span>&#160;</pre>

<pre class="alt"><span class="lnum">  23:  </span>        mRayLayout = (RayLayout) findViewById(R.id.item_layout);</pre>

<pre><span class="lnum">  24:  </span>&#160;</pre>

<pre class="alt"><span class="lnum">  25:  </span>        final ViewGroup controlLayout = (ViewGroup) findViewById(R.id.control_layout);</pre>

<pre><span class="lnum">  26:  </span>        controlLayout.setClickable(<span class="kwrd">true</span>);</pre>

<pre class="alt"><span class="lnum">  27:  </span>        controlLayout.setOnTouchListener(<span class="kwrd">new</span> OnTouchListener() {</pre>

<pre><span class="lnum">  28:  </span>&#160;</pre>

<pre class="alt"><span class="lnum">  29:  </span>            @Override</pre>

<pre><span class="lnum">  30:  </span>            <span class="kwrd">public</span> boolean onTouch(View v, MotionEvent <span class="kwrd">event</span>) {</pre>

<pre class="alt"><span class="lnum">  31:  </span>                <span class="kwrd">if</span> (<span class="kwrd">event</span>.getAction() == MotionEvent.ACTION_DOWN) {</pre>

<pre><span class="lnum">  32:  </span>                    mHintView.startAnimation(createHintSwitchAnimation(mRayLayout.isExpanded()));</pre>

<pre class="alt"><span class="lnum">  33:  </span>                    mRayLayout.switchState(<span class="kwrd">true</span>);</pre>

<pre><span class="lnum">  34:  </span>                }</pre>

<pre class="alt"><span class="lnum">  35:  </span>&#160;</pre>

<pre><span class="lnum">  36:  </span>                <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre>

<pre class="alt"><span class="lnum">  37:  </span>            }</pre>

<pre><span class="lnum">  38:  </span>        });</pre>

<pre class="alt"><span class="lnum">  39:  </span>&#160;</pre>

<pre><span class="lnum">  40:  </span>        mHintView = (ImageView) findViewById(R.id.control_hint);</pre>

<pre class="alt"><span class="lnum">  41:  </span>    }</pre>

</div> <style type="text/css">app

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>composer

<p></p>框架

<p>&#160;&#160;&#160;&#160;&#160;&#160; RayMenu繼承於RelativeLayout, 向其餘視圖類同樣,先調用父類的構造函數,而後就是本身的init(),在這裏設置本身的高度依賴本身的內容,寬度與父視圖同樣寬。setClipChildren(<span class="kwrd">false</span>);傳遞給子控件進行繪製的canvas不剪切,這能夠保證,當子控件的動畫效果超出自己佈局範圍時,依然可見。</p>

<p>而後就是將佈局文件添加進來,設置紅色按鈕的監聽事件。</p>

<p>&#160;&#160;&#160;&#160;&#160;&#160; 將佈局文件添加進來時,又發生了子控件的實例化,這裏主要講一下Raylayout類的實例化過程。</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">class</span> RayLayout extends ViewGroup {</pre>

<pre><span class="lnum"> 2: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 3: </span> <span class="rem">/**</span></pre>

<pre><span class="lnum"> 4: </span><span class="rem"> * children will be set the same size.</span></pre>

<pre class="alt"><span class="lnum"> 5: </span><span class="rem"> */</span></pre>

<pre><span class="lnum"> 6: </span> <span class="kwrd">private</span> <span class="kwrd">int</span> mChildSize;</pre>

<pre class="alt"><span class="lnum"> 7: </span>&#160;</pre>

<pre><span class="lnum"> 8: </span> <span class="rem">/* the distance between child Views */</span></pre>

<pre class="alt"><span class="lnum"> 9: </span> <span class="kwrd">private</span> <span class="kwrd">int</span> mChildGap;</pre>

<pre><span class="lnum"> 10: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 11: </span> <span class="rem">/* left space to place the switch button */</span></pre>

<pre><span class="lnum"> 12: </span> <span class="kwrd">private</span> <span class="kwrd">int</span> mLeftHolderWidth;</pre>

<pre class="alt"><span class="lnum"> 13: </span>&#160;</pre>

<pre><span class="lnum"> 14: </span> <span class="kwrd">private</span> boolean mExpanded = <span class="kwrd">false</span>;</pre>

<pre class="alt"><span class="lnum"> 15: </span>&#160;</pre>

<pre><span class="lnum"> 16: </span> <span class="kwrd">public</span> RayLayout(Context context) {</pre>

<pre class="alt"><span class="lnum"> 17: </span> super(context);</pre>

<pre><span class="lnum"> 18: </span> }</pre>

<pre class="alt"><span class="lnum"> 19: </span>&#160;</pre>

<pre><span class="lnum"> 20: </span> <span class="kwrd">public</span> RayLayout(Context context, AttributeSet attrs) {</pre>

<pre class="alt"><span class="lnum"> 21: </span> super(context, attrs);</pre>

<pre><span class="lnum"> 22: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 23: </span> <span class="kwrd">if</span> (attrs != <span class="kwrd">null</span>) {</pre>

<pre><span class="lnum"> 24: </span> TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ArcLayout, 0, 0);</pre>

<pre class="alt"><span class="lnum"> 25: </span> mChildSize = Math.max(a.getDimensionPixelSize(R.styleable.ArcLayout_childSize, 0), 0);</pre>

<pre><span class="lnum"> 26: </span> a.recycle();</pre>

<pre class="alt"><span class="lnum"> 27: </span>&#160;</pre>

<pre><span class="lnum"> 28: </span> a = getContext().obtainStyledAttributes(attrs, R.styleable.RayLayout, 0, 0);</pre>

<pre class="alt"><span class="lnum"> 29: </span> mLeftHolderWidth = Math.max(a.getDimensionPixelSize(R.styleable.RayLayout_leftHolderWidth, 0), 0);</pre>

<pre><span class="lnum"> 30: </span> a.recycle();</pre>

<pre class="alt"><span class="lnum"> 31: </span>&#160;</pre>

<pre><span class="lnum"> 32: </span> }</pre>

<pre class="alt"><span class="lnum"> 33: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p></p>

<p>&#160;&#160;&#160;&#160;&#160; 這個就更簡單了,得到一些xml中的屬性,好比重要的mchildSize和mLeftHolderWidth。初始化的工做仍是很簡單的,固然activity中的setContent()函數中發生了不少事情,這個之後有機會再講,可是經過這個過程,咱們就將視圖set到了window上了。開始等待着繪製的消息,關於繪製過程的詳細過程推薦閱讀,<a href="http://blog.csdn.net/qinjuning/article/details/7110211">Android中View繪製流程以及invalidate()等相關方法分析</a>。</p>

<p>&#160;&#160;&#160; </p>

<h3>menusure過程:</h3>

<p>&#160; RayMenu.onMeasure()會調用RayMenu.Measure()函數,進而執行onMeasure():</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">int</span> computeChildGap(final <span class="kwrd">float</span> width, final <span class="kwrd">int</span> childCount, final <span class="kwrd">int</span> childSize, final <span class="kwrd">int</span> minGap) {</pre>

<pre><span class="lnum"> 2: </span> <span class="kwrd">return</span> Math.max((<span class="kwrd">int</span>) (width / childCount - childSize), minGap);</pre>

<pre class="alt"><span class="lnum"> 3: </span> }</pre>

<pre><span class="lnum"> 4: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 5: </span> @Override</pre>

<pre><span class="lnum"> 6: </span> <span class="kwrd">protected</span> <span class="kwrd">int</span> getSuggestedMinimumHeight() {</pre>

<pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">return</span> mChildSize;</pre>

<pre><span class="lnum"> 8: </span> }</pre>

<pre class="alt"><span class="lnum"> 9: </span>&#160;</pre>

<pre><span class="lnum"> 10: </span> @Override</pre>

<pre class="alt"><span class="lnum"> 11: </span> <span class="kwrd">protected</span> <span class="kwrd">int</span> getSuggestedMinimumWidth() {</pre>

<pre><span class="lnum"> 12: </span> <span class="kwrd">return</span> mLeftHolderWidth + mChildSize * getChildCount();</pre>

<pre class="alt"><span class="lnum"> 13: </span> }</pre>

<pre><span class="lnum"> 14: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 15: </span> @Override</pre>

<pre><span class="lnum"> 16: </span> <span class="kwrd">protected</span> <span class="kwrd">void</span> onMeasure(<span class="kwrd">int</span> widthMeasureSpec, <span class="kwrd">int</span> heightMeasureSpec) {</pre>

<pre class="alt"><span class="lnum"> 17: </span> super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getSuggestedMinimumHeight(), MeasureSpec.EXACTLY));</pre>

<pre><span class="lnum"> 18: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 19: </span> final <span class="kwrd">int</span> count = getChildCount();</pre>

<pre><span class="lnum"> 20: </span> mChildGap = computeChildGap(getMeasuredWidth() - mLeftHolderWidth, count, mChildSize, 0);</pre>

<pre class="alt"><span class="lnum"> 21: </span>&#160;</pre>

<pre><span class="lnum"> 22: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; count; i++) {</pre>

<pre class="alt"><span class="lnum"> 23: </span> getChildAt(i).measure(MeasureSpec.makeMeasureSpec(mChildSize, MeasureSpec.EXACTLY),</pre>

<pre><span class="lnum"> 24: </span> MeasureSpec.makeMeasureSpec(mChildSize, MeasureSpec.EXACTLY));</pre>

<pre class="alt"><span class="lnum"> 25: </span> }</pre>

<pre><span class="lnum"> 26: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p>1. 調用View.onMeasure(),這一步會肯定控件的寬度與父視圖同樣寬,由於RayMenu設置的寬度fill_parent,且RayLayout設置的也是fill_parent,致使這裏measure的寬度爲屏幕寬度,高度爲getSuggestionMinimumHeight(),即mChildSize的高度。</p>

<p>2. 肯定menu item之間的距離mChildGap</p>

<p>3. measure了menu item的大小,顯然其高寬爲mChildSize。</p>

<h3>Layout過程:</h3>

<p>過程與measure相似。</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">private</span> <span class="kwrd">static</span> Rect computeChildFrame(final boolean expanded, final <span class="kwrd">int</span> paddingLeft, final <span class="kwrd">int</span> childIndex,</pre>

<pre><span class="lnum"> 2: </span> final <span class="kwrd">int</span> gap, final <span class="kwrd">int</span> size) {</pre>

<pre class="alt"><span class="lnum"> 3: </span> final <span class="kwrd">int</span> left = expanded ? (paddingLeft + childIndex * (gap + size) + gap) : ((paddingLeft - size) / 2);</pre>

<pre><span class="lnum"> 4: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">return</span> <span class="kwrd">new</span> Rect(left, 0, left + size, size);</pre>

<pre><span class="lnum"> 6: </span> }</pre>

<pre class="alt"><span class="lnum"> 7: </span>&#160;</pre>

<pre><span class="lnum"> 8: </span> @Override</pre>

<pre class="alt"><span class="lnum"> 9: </span> <span class="kwrd">protected</span> <span class="kwrd">void</span> onLayout(boolean changed, <span class="kwrd">int</span> l, <span class="kwrd">int</span> t, <span class="kwrd">int</span> r, <span class="kwrd">int</span> b) {</pre>

<pre><span class="lnum"> 10: </span> final <span class="kwrd">int</span> paddingLeft = mLeftHolderWidth;</pre>

<pre class="alt"><span class="lnum"> 11: </span> final <span class="kwrd">int</span> childCount = getChildCount();</pre>

<pre><span class="lnum"> 12: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; childCount; i++) {</pre>

<pre><span class="lnum"> 14: </span> Rect frame = computeChildFrame(mExpanded, paddingLeft, i, mChildGap, mChildSize);</pre>

<pre class="alt"><span class="lnum"> 15: </span> getChildAt(i).layout(frame.left, frame.top, frame.right, frame.bottom);</pre>

<pre><span class="lnum"> 16: </span> }</pre>

<pre class="alt"><span class="lnum"> 17: </span>&#160;</pre>

<pre><span class="lnum"> 18: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p></p>

<p>這個過程直接影響着menu item的佈局,能夠看到當expand時會呈直線排列,不然,則其中心與紅色按鈕的中心的x值同樣。</p>

<h3>Draw過程:</h3>

<p>調用父類的函數完成。這裏再也不贅述。</p>

<h3>事件驅動:</h3>

<p>再回到使用RayMenu的步驟上來,而後就是添加Menu Item和監聽事件:</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> <span class="kwrd">static</span> final <span class="kwrd">int</span>[] ITEM_DRAWABLES = { R.drawable.composer_camera, R.drawable.composer_music,</pre>

<pre><span class="lnum"> 2: </span> R.drawable.composer_place, R.drawable.composer_sleep, R.drawable.composer_thought, R.drawable.composer_with };</pre>

<pre class="alt"><span class="lnum"> 3: </span>&#160;</pre>

<pre><span class="lnum"> 4: </span>final <span class="kwrd">int</span> itemCount = ITEM_DRAWABLES.length;</pre>

<pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; itemCount; i++) {</pre>

<pre><span class="lnum"> 6: </span> ImageView item = <span class="kwrd">new</span> ImageView(<span class="kwrd">this</span>);</pre>

<pre class="alt"><span class="lnum"> 7: </span> item.setImageResource(ITEM_DRAWABLES[i]);</pre>

<pre><span class="lnum"> 8: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 9: </span> final <span class="kwrd">int</span> position = i;</pre>

<pre><span class="lnum"> 10: </span> rayMenu.addItem(item, <span class="kwrd">new</span> OnClickListener() {</pre>

<pre class="alt"><span class="lnum"> 11: </span>&#160;</pre>

<pre><span class="lnum"> 12: </span> @Override</pre>

<pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> onClick(View v) {</pre>

<pre><span class="lnum"> 14: </span> Toast.makeText(MainActivity.<span class="kwrd">this</span>, <span class="str">&quot;position:&quot;</span> + position, Toast.LENGTH_SHORT).show();</pre>

<pre class="alt"><span class="lnum"> 15: </span> }</pre>

<pre><span class="lnum"> 16: </span> });<span class="rem">// Add a menu item</span></pre>

<pre class="alt"><span class="lnum"> 17: </span> }</pre>

<pre><span class="lnum"> 18: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p>完成這些後,就等待着RayMenu的在屏幕上出現了,你會看到一個紅色的button,但爲何是紅色的button而不是menu Item中的一個,顯然這個時候Menu Item與紅色Button應該重合,這涉及到view Z-order,由於在<a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/res/layout/ray_menu.xml">ray_menu.xml</a>中controlLayout出如今rayLayout以後,在繪製的時候,若二者有重疊,則後添加進來的view會出如今上面。</p>

<p>當咱們點擊紅色Button後,而後便進行了消息事件的傳遞(<a href="http://blog.csdn.net/singwhatiwanna/article/details/17339857">Android源碼分析-點擊事件派發機制</a>), 這後便調用了</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span>controlLayout.setOnTouchListener(<span class="kwrd">new</span> OnTouchListener() {</pre>

<pre><span class="lnum"> 2: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 3: </span> @Override</pre>

<pre><span class="lnum"> 4: </span> <span class="kwrd">public</span> boolean onTouch(View v, MotionEvent <span class="kwrd">event</span>) {</pre>

<pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">if</span> (<span class="kwrd">event</span>.getAction() == MotionEvent.ACTION_DOWN) {</pre>

<pre><span class="lnum"> 6: </span> mHintView.startAnimation(createHintSwitchAnimation(mRayLayout.isExpanded()));</pre>

<pre class="alt"><span class="lnum"> 7: </span> mRayLayout.switchState(<span class="kwrd">true</span>);</pre>

<pre><span class="lnum"> 8: </span> }</pre>

<pre class="alt"><span class="lnum"> 9: </span>&#160;</pre>

<pre><span class="lnum"> 10: </span> <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre>

<pre class="alt"><span class="lnum"> 11: </span> }</pre>

<pre><span class="lnum"> 12: </span> });</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p>這裏我比較費解的是爲甚要使用OntouchListener,就代碼而言,應該是想不佔用其餘監聽名額。不過這致使手指一按下就會彈出菜單。咱們繼續往下進入mRayLayout.switchState(true)的代碼。</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span> <span class="rem">/**</span></pre>

<pre><span class="lnum"> 2: </span><span class="rem"> * switch between expansion and shrinkage</span></pre>

<pre class="alt"><span class="lnum"> 3: </span><span class="rem"> * </span></pre>

<pre><span class="lnum"> 4: </span><span class="rem"> * @param showAnimation</span></pre>

<pre class="alt"><span class="lnum"> 5: </span><span class="rem"> */</span></pre>

<pre><span class="lnum"> 6: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> switchState(final boolean showAnimation) {</pre>

<pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">if</span> (showAnimation) {</pre>

<pre><span class="lnum"> 8: </span> final <span class="kwrd">int</span> childCount = getChildCount();</pre>

<pre class="alt"><span class="lnum"> 9: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; childCount; i++) {</pre>

<pre><span class="lnum"> 10: </span> bindChildAnimation(getChildAt(i), i, 300);</pre>

<pre class="alt"><span class="lnum"> 11: </span> }</pre>

<pre><span class="lnum"> 12: </span> }</pre>

<pre class="alt"><span class="lnum"> 13: </span>&#160;</pre>

<pre><span class="lnum"> 14: </span> mExpanded = !mExpanded;</pre>

<pre class="alt"><span class="lnum"> 15: </span>&#160;</pre>

<pre><span class="lnum"> 16: </span> <span class="kwrd">if</span> (!showAnimation) {</pre>

<pre class="alt"><span class="lnum"> 17: </span> requestLayout();</pre>

<pre><span class="lnum"> 18: </span> }</pre>

<pre class="alt"><span class="lnum"> 19: </span>&#160;</pre>

<pre><span class="lnum"> 20: </span> invalidate();</pre>

<pre class="alt"><span class="lnum"> 21: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p></p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> <span class="kwrd">void</span> onAllAnimationsEnd() {</pre>

<pre><span class="lnum"> 2: </span> final <span class="kwrd">int</span> childCount = getChildCount();</pre>

<pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; childCount; i++) {</pre>

<pre><span class="lnum"> 4: </span> getChildAt(i).clearAnimation();</pre>

<pre class="alt"><span class="lnum"> 5: </span> }</pre>

<pre><span class="lnum"> 6: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 7: </span> requestLayout();</pre>

<pre><span class="lnum"> 8: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p>給子類添加動畫,什麼動畫呢?就是彈出和旋轉動畫。而後expand的值變化了,再而後重繪,這樣一樣會使得動畫啓動(<a href="http://www.ibm.com/developerworks/cn/opensource/os-cn-android-anmt1/index.html?ca=dat">Android 動畫框架詳解,第 1 部分</a> ),但不會致使從新layout,等到動畫都結束後,會調用onAllAnimationsEnd,會調用requestlayout,這樣會引發從新佈局,便回到了前面講到的onLayout函數。當menu打開了,咱們點擊了一下item則會調用item的監聽函數。</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> OnClickListener getItemClickListener(final OnClickListener listener) {</pre>

<pre><span class="lnum"> 2: </span> <span class="kwrd">return</span> <span class="kwrd">new</span> OnClickListener() {</pre>

<pre class="alt"><span class="lnum"> 3: </span>&#160;</pre>

<pre><span class="lnum"> 4: </span> @Override</pre>

<pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> onClick(final View viewClicked) {</pre>

<pre><span class="lnum"> 6: </span> Animation animation = bindItemAnimation(viewClicked, <span class="kwrd">true</span>, 400);</pre>

<pre class="alt"><span class="lnum"> 7: </span> animation.setAnimationListener(<span class="kwrd">new</span> AnimationListener() {</pre>

<pre><span class="lnum"> 8: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 9: </span> @Override</pre>

<pre><span class="lnum"> 10: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> onAnimationStart(Animation animation) {</pre>

<pre class="alt"><span class="lnum"> 11: </span>&#160;</pre>

<pre><span class="lnum"> 12: </span> }</pre>

<pre class="alt"><span class="lnum"> 13: </span>&#160;</pre>

<pre><span class="lnum"> 14: </span> @Override</pre>

<pre class="alt"><span class="lnum"> 15: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> onAnimationRepeat(Animation animation) {</pre>

<pre><span class="lnum"> 16: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 17: </span> }</pre>

<pre><span class="lnum"> 18: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 19: </span> @Override</pre>

<pre><span class="lnum"> 20: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> onAnimationEnd(Animation animation) {</pre>

<pre class="alt"><span class="lnum"> 21: </span> postDelayed(<span class="kwrd">new</span> Runnable() {</pre>

<pre><span class="lnum"> 22: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 23: </span> @Override</pre>

<pre><span class="lnum"> 24: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> run() {</pre>

<pre class="alt"><span class="lnum"> 25: </span> itemDidDisappear();</pre>

<pre><span class="lnum"> 26: </span> }</pre>

<pre class="alt"><span class="lnum"> 27: </span> }, 0);</pre>

<pre><span class="lnum"> 28: </span> }</pre>

<pre class="alt"><span class="lnum"> 29: </span> });</pre>

<pre><span class="lnum"> 30: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 31: </span> final <span class="kwrd">int</span> itemCount = mRayLayout.getChildCount();</pre>

<pre><span class="lnum"> 32: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; itemCount; i++) {</pre>

<pre class="alt"><span class="lnum"> 33: </span> View item = mRayLayout.getChildAt(i);</pre>

<pre><span class="lnum"> 34: </span> <span class="kwrd">if</span> (viewClicked != item) {</pre>

<pre class="alt"><span class="lnum"> 35: </span> bindItemAnimation(item, <span class="kwrd">false</span>, 300);</pre>

<pre><span class="lnum"> 36: </span> }</pre>

<pre class="alt"><span class="lnum"> 37: </span> }</pre>

<pre><span class="lnum"> 38: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 39: </span> mRayLayout.invalidate();</pre>

<pre><span class="lnum"> 40: </span> mHintView.startAnimation(createHintSwitchAnimation(<span class="kwrd">true</span>));</pre>

<pre class="alt"><span class="lnum"> 41: </span>&#160;</pre>

<pre><span class="lnum"> 42: </span> <span class="kwrd">if</span> (listener != <span class="kwrd">null</span>) {</pre>

<pre class="alt"><span class="lnum"> 43: </span> listener.onClick(viewClicked);</pre>

<pre><span class="lnum"> 44: </span> }</pre>

<pre class="alt"><span class="lnum"> 45: </span> }</pre>

<pre><span class="lnum"> 46: </span> };</pre>

<pre class="alt"><span class="lnum"> 47: </span> }</pre>

</div>

<div class="csharpcode">&#160;</div>

<p>和上一個同樣,添加動畫,被點擊的item和其餘item會被添加不一樣的動畫,當動畫結束後便會調用itemDIdDisappear():</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> <span class="kwrd">void</span> itemDidDisappear() {</pre>

<pre><span class="lnum"> 2: </span> final <span class="kwrd">int</span> itemCount = mRayLayout.getChildCount();</pre>

<pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; itemCount; i++) {</pre>

<pre><span class="lnum"> 4: </span> View item = mRayLayout.getChildAt(i);</pre>

<pre class="alt"><span class="lnum"> 5: </span> item.clearAnimation();</pre>

<pre><span class="lnum"> 6: </span> }</pre>

<pre class="alt"><span class="lnum"> 7: </span>&#160;</pre>

<pre><span class="lnum"> 8: </span> mRayLayout.switchState(<span class="kwrd">false</span>);</pre>

<pre class="alt"><span class="lnum"> 9: </span> }</pre>

</div>

<div class="csharpcode">&#160;</div>

<p>還記得以前講的setClipChildren(false); 被點擊的item有一個放大的動畫,若不設置這個屬性,則致使放大效果的上下部分都看不到。這涉及到canvas的剪裁,默認的父控件在調用子控件的draw函數時會,剪裁canvas是其尺寸爲分配給子控件的大小。你不妨將menu Item的大小和紅色Button的大小設成同樣。就會發現會有一些問題。</p>

<blockquote> <h2 align="center">RayMenu的改進:</h2> </blockquote>

<h3>可以讓其放在兩側:</h3>

<p>RayMenu只能從左向右彈出,有時候不能適應屏幕布局。</p>

<p>固然實現的方式有不少種,可是都要解決兩個問題,1. controlLayout的位置&#160; 2. 根據controlLayout的位置變換item的佈局和動畫</p>

<p>這裏講一個最簡單的,也是最粗暴的。由於Item動畫的設置,是根據子Item的佈局位置來的。因此控制好Item佈局就可以知足第2點。至於第1點,不能在xml中設置,由於使用的merge,將會被RelativeLayout替換掉,android:layout_gravity不會有什麼做用。</p>

<p>RayMenu.java</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">public</span> <span class="kwrd">void</span> setHolderSide(boolean right) {</pre>

<pre><span class="lnum"> 2: </span> mRayLayout.setHolderSide(right);</pre>

<pre class="alt"><span class="lnum"> 3: </span> LayoutParams lp = (LayoutParams) findViewById(R.id.control_layout).getLayoutParams();</pre>

<pre><span class="lnum"> 4: </span> <span class="kwrd">if</span> (right) {</pre>

<pre class="alt"><span class="lnum"> 5: </span> lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);</pre>

<pre><span class="lnum"> 6: </span> lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);</pre>

<pre class="alt"><span class="lnum"> 7: </span> } <span class="kwrd">else</span> {</pre>

<pre><span class="lnum"> 8: </span> lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);</pre>

<pre class="alt"><span class="lnum"> 9: </span> lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);</pre>

<pre><span class="lnum"> 10: </span> }</pre>

<pre class="alt"><span class="lnum"> 11: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p>RayLayout.java</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> boolean mHolderSide = <span class="kwrd">false</span>;</pre>

<pre><span class="lnum"> 2: </span> </pre>

<pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> setHolderSide(boolean right) {</pre>

<pre><span class="lnum"> 4: </span> mHolderSide = right;</pre>

<pre class="alt"><span class="lnum"> 5: </span> }</pre>

<pre><span class="lnum"> 6: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">private</span> Rect computeChildFrame(final boolean expanded, final <span class="kwrd">int</span> paddingLeft, final <span class="kwrd">int</span> childIndex,</pre>

<pre><span class="lnum"> 8: </span> final <span class="kwrd">int</span> gap, final <span class="kwrd">int</span> size) {</pre>

<pre class="alt"><span class="lnum"> 9: </span> <span class="kwrd">int</span> left = expanded ? (paddingLeft + childIndex * (gap + size) + gap) : ((paddingLeft - size) / 2);</pre>

<pre><span class="lnum"> 10: </span> <span class="kwrd">if</span> (mHolderSide) {</pre>

<pre class="alt"><span class="lnum"> 11: </span> left = getMeasuredWidth() - (left + size);</pre>

<pre><span class="lnum"> 12: </span> }</pre>

<pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd">return</span> <span class="kwrd">new</span> Rect(left, 0, left + size, size);</pre>

<pre><span class="lnum"> 14: </span> }</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p></p>

<p>在你使用的java文件中添加</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span>rayMenu.setHolderSide(<span class="kwrd">true</span>);</pre> </div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p></p>

<h3>當Item很大時,1.關閉RayMenu後,紅色Button不能擋住item&#160; 2.item被點擊時,出現的放大效果時上下部分會被截斷。</h3>

<p>咱們不是設置了RayMenu的setClipChildren(false);嗎?爲甚還會出現這種狀況,由於這個設置只對RayMenu內部的canvas傳遞有效,RayMenu設置的高度爲LayoutParams.WRAP_CONTENT,因此最大也就是Max(紅色button的高度,item的size),當item動畫的高度超過RayMenu的高度時就會出現這種狀況。</p>

<p>針對第1個問題,有兩種解決辦法:1.當關閉Raymenu後會有從新佈局的機會,這個時候能夠控制其佈局,這個不推薦,由於佈局還涉及到動畫等等一些問題。</p>

<p>2. 當關閉Raymenu後,簡單粗暴的將rayLayout設置爲invisible就能夠了,在這裏要注意的設置爲invisible和gone會對動畫產生很大的不一樣(我並不清楚具體緣由,不過在viewGroup的drawchild()函數中應該能找到緣由)。</p>

<p>RayLayout.java</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> switchState(final boolean showAnimation) {</pre>

<pre><span class="lnum"> 2: </span> <span class="kwrd">if</span> (showAnimation) {</pre>

<pre class="alt"><span class="lnum"> 3: </span> final <span class="kwrd">int</span> childCount = getChildCount();</pre>

<pre><span class="lnum"> 4: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; childCount; i++) {</pre>

<pre class="alt"><span class="lnum"> 5: </span> bindChildAnimation(getChildAt(i), i, 300);</pre>

<pre><span class="lnum"> 6: </span> }</pre>

<pre class="alt"><span class="lnum"> 7: </span> }</pre>

<pre><span class="lnum"> 8: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 9: </span> mExpanded = !mExpanded;</pre>

<pre><span class="lnum"> 10: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 11: </span> <span class="kwrd">if</span> (!showAnimation) {</pre>

<pre><span class="lnum"> 12: </span> <span class="kwrd">if</span> (!mExpanded) {</pre>

<pre class="alt"><span class="lnum"> 13: </span> setVisibility(GONE);</pre>

<pre><span class="lnum"> 14: </span> }</pre>

<pre class="alt"><span class="lnum"> 15: </span> requestLayout();</pre>

<pre><span class="lnum"> 16: </span> }</pre>

<pre class="alt"><span class="lnum"> 17: </span>&#160;</pre>

<pre><span class="lnum"> 18: </span> invalidate();</pre>

<pre class="alt"><span class="lnum"> 19: </span> }</pre>

<pre><span class="lnum"> 20: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 21: </span> <span class="kwrd">private</span> <span class="kwrd">void</span> onAllAnimationsEnd() {</pre>

<pre><span class="lnum"> 22: </span> final <span class="kwrd">int</span> childCount = getChildCount();</pre>

<pre class="alt"><span class="lnum"> 23: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; childCount; i++) {</pre>

<pre><span class="lnum"> 24: </span> getChildAt(i).clearAnimation();</pre>

<pre class="alt"><span class="lnum"> 25: </span> }</pre>

<pre><span class="lnum"> 26: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 27: </span> <span class="kwrd">if</span> (!mExpanded) {</pre>

<pre><span class="lnum"> 28: </span> setVisibility(INVISIBLE);</pre>

<pre class="alt"><span class="lnum"> 29: </span> }</pre>

<pre><span class="lnum"> 30: </span> requestLayout();</pre>

<pre class="alt"><span class="lnum"> 31: </span> }</pre>

<pre><span class="lnum"> 32: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 33: </span>}</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p>RayMenu.java</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span>controlLayout.setOnTouchListener(<span class="kwrd">new</span> OnTouchListener() {</pre>

<pre><span class="lnum"> 2: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 3: </span> @Override</pre>

<pre><span class="lnum"> 4: </span> <span class="kwrd">public</span> boolean onTouch(View v, MotionEvent <span class="kwrd">event</span>) {</pre>

<pre class="alt"><span class="lnum"> 5: </span> <span class="kwrd">if</span> (<span class="kwrd">event</span>.getAction() == MotionEvent.ACTION_DOWN) {</pre>

<pre><span class="lnum"> 6: </span> mHintView.startAnimation(createHintSwitchAnimation(mRayLayout.isExpanded()));</pre>

<pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">if</span> (!mRayLayout.isExpanded()) {</pre>

<pre><span class="lnum"> 8: </span> mRayLayout.setVisibility(VISIBLE);</pre>

<pre class="alt"><span class="lnum"> 9: </span> }</pre>

<pre><span class="lnum"> 10: </span> mRayLayout.switchState(<span class="kwrd">true</span>);</pre>

<pre class="alt"><span class="lnum"> 11: </span> }</pre>

<pre><span class="lnum"> 12: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre>

<pre><span class="lnum"> 14: </span> }</pre>

<pre class="alt"><span class="lnum"> 15: </span> });</pre>

</div> <style type="text/css">

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>

<p></p>

<p>針對第2個問題,有兩種解決辦法:1. 將RayMenu的父控件也一樣設置爲setClipChildren(false); 2. 因爲放大動畫是發大2倍。</p>

<p>RayLayout.java</p>

<div class="csharpcode"> <pre class="alt"><span class="lnum"> 1: </span><span class="kwrd">private</span> Rect computeChildFrame(final boolean expanded, final <span class="kwrd">int</span> paddingLeft, final <span class="kwrd">int</span> childIndex,</pre>

<pre><span class="lnum"> 2: </span> final <span class="kwrd">int</span> gap, final <span class="kwrd">int</span> size) {</pre>

<pre class="alt"><span class="lnum"> 3: </span> <span class="kwrd">int</span> left = expanded ? (paddingLeft + childIndex * (gap + size) + gap) : ((paddingLeft - size) / 2);</pre>

<pre><span class="lnum"> 4: </span> <span class="kwrd">if</span> (mHolderSide) {</pre>

<pre class="alt"><span class="lnum"> 5: </span> left = getMeasuredWidth() - (left + size);</pre>

<pre><span class="lnum"> 6: </span> }</pre>

<pre class="alt"><span class="lnum"> 7: </span> <span class="kwrd">int</span> top = (getSuggestedMinimumHeight()-size)/2;</pre>

<pre><span class="lnum"> 8: </span> <span class="kwrd">return</span> <span class="kwrd">new</span> Rect(left, top, left + size, top+size);</pre>

<pre class="alt"><span class="lnum"> 9: </span> }</pre>

<pre><span class="lnum"> 10: </span>&#160;</pre>

<pre class="alt"><span class="lnum"> 11: </span> @Override</pre>

<pre><span class="lnum"> 12: </span> <span class="kwrd">protected</span> <span class="kwrd">int</span> getSuggestedMinimumHeight() {</pre>

<pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd">return</span> mChildSize * 2;</pre>

<pre><span class="lnum"> 14: </span> }</pre>

</div>

<p>第1種解決辦法更好一些。</p>

<p>還有另一些變態要求,好比當RayMenu關閉後,可以隨便移動,便可以拖拽紅色Button。而且還要知足前面的要求。</p>

<p>我寫了一個例子,這裏就不詳細講了。放一個鏈接<a title="http://pan.baidu.com/share/link?shareid=1437532240&amp;uk=405092275" href="http://pan.baidu.com/share/link?shareid=1437532240&amp;uk=405092275">http://pan.baidu.com/share/link?shareid=1437532240&amp;uk=405092275</a>。</p>

相關文章
相關標籤/搜索