<p>    从如今开始,我将写下因为项目而接触到的优秀的Android开源项目的学习理解。一来有助于本身的提升,方便之后的查阅;二来学习Android须要有开源的精神,和别人分享是很重要的。我如今对Android应用开发的理解还不深,但愿能在这个过程当中,迅速的成长起来。</p> <p>    废话很少说,先展现一下,ArcMenu & 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>       其涉及的知识,是ViewGroup的布局与Android动画。因为ArcMenu & RayMenu实质上是同样的,只是ArcMenu布局计算上稍显复复杂一些,故选择其RayMenu做为例子来说,柿子仍是得捡软的捏呀。</p> <p>      RayMenu的用到的几个文件以下:</p> <p>      <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/src/com/capricorn/RayLayout.java">RayLayout.java</a>——用于控制弹出菜单的动画与布局</p> <p>      <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/src/com/capricorn/RayMenu.java">RayMenu.java</a>——用于控制控件的逻辑,好比按下红色按钮后,弹出菜单等。</p> <p>      <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/src/com/capricorn/RotateAndTranslateAnimation.java">RotateAndTranslateAnimation.java</a>——这只是个动画</p> <p>      <a href="https://github.com/daCapricorn/ArcMenu/blob/master/library/res/layout/ray_menu.xml">ray_menu.xml</a>——rayMenu的布局文件</p> <p></p> <p>              关于它的使用方法,很简单,见<a href="https://github.com/daCapricorn/ArcMenu/blob/master/sample/src/com/capricorn/example/MainActivity.java">MainActivity.java</a>。</p> <p>              下面,我就从咱们使用的流程开始说,</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> </pre> <pre><span class="lnum"> 4: </span> <span class="kwrd">private</span> ImageView mHintView;</pre> <pre class="alt"><span class="lnum"> 5: </span> </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> </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> </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> </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> </pre> <pre class="alt"><span class="lnum"> 23: </span> mRayLayout = (RayLayout) findViewById(R.id.item_layout);</pre> <pre><span class="lnum"> 24: </span> </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> </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> </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> </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>       RayMenu继承于RelativeLayout, 向其余视图类同样,先调用父类的构造函数,而后就是本身的init(),在这里设置本身的高度依赖本身的内容,宽度与父视图同样宽。setClipChildren(<span class="kwrd">false</span>);传递给子控件进行绘制的canvas不剪切,这能够保证,当子控件的动画效果超出自己布局范围时,依然可见。</p>
<p>而后就是将布局文件添加进来,设置红色按钮的监听事件。</p>
<p>       将布局文件添加进来时,又发生了子控件的实例化,这里主要讲一下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> </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> </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> </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> </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> </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> </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> </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> </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> </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>      这个就更简单了,得到一些xml中的属性,好比重要的mchildSize和mLeftHolderWidth。初始化的工做仍是很简单的,固然activity中的setContent()函数中发生了不少事情,这个之后有机会再讲,可是经过这个过程,咱们就将视图set到了window上了。开始等待着绘制的消息,关于绘制过程的详细过程推荐阅读,<a href="http://blog.csdn.net/qinjuning/article/details/7110211">Android中View绘制流程以及invalidate()等相关方法分析</a>。</p>
<p>    </p>
<h3>menusure过程:</h3>
<p>  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> </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> </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> </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> </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> </pre>
<pre><span class="lnum"> 22: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i < 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> </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> </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> </pre>
<pre class="alt"><span class="lnum"> 13: </span> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i < 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> </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> </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 < 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> </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> </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">"position:"</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> </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> </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 < 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> </pre>
<pre><span class="lnum"> 14: </span> mExpanded = !mExpanded;</pre>
<pre class="alt"><span class="lnum"> 15: </span> </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> </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 < 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> </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> </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> </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> </pre>
<pre><span class="lnum"> 12: </span> }</pre>
<pre class="alt"><span class="lnum"> 13: </span> </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> </pre>
<pre class="alt"><span class="lnum"> 17: </span> }</pre>
<pre><span class="lnum"> 18: </span> </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> </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> </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 < 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> </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> </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"> </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 < 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> </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"> </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的位置  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> </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  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 < 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> </pre>
<pre class="alt"><span class="lnum"> 9: </span> mExpanded = !mExpanded;</pre>
<pre><span class="lnum"> 10: </span> </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> </pre>
<pre><span class="lnum"> 18: </span> invalidate();</pre>
<pre class="alt"><span class="lnum"> 19: </span> }</pre>
<pre><span class="lnum"> 20: </span> </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 < 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> </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> </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> </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> </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> </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&uk=405092275" href="http://pan.baidu.com/share/link?shareid=1437532240&uk=405092275">http://pan.baidu.com/share/link?shareid=1437532240&uk=405092275</a>。</p>