Android自定义控件实战——仿淘宝商品浏览界面

转载出处http://blog.csdn.net/zhongkejingwang/article/details/38656929 用手机淘宝浏览商品详情时,商品图片是放在后面的,在第一个ScrollView滚动到最底下时会有提示,继续拖动才能浏览图片。仿照这个效果写一个出来并不难,只要定义一个Layout管理两个ScrollView就行了,当第一个ScrollView滑到底部时,再次向上滑动进入第二个ScrollView。效果如下: 需要注意的地方是: 1、如果是手动滑到底部需要再次按下才能继续往下滑,自动滚动到底部则不需要 2、在由上一个ScrollView滑动到下一个ScrollView的过程中多只手指相继拖动也不会导致布局的剧变,也就是多个pointer的滑动不会导致move距离的剧变。 这个Layout的实现思路是: 在布局中放置两个ScrollView,并为其设置OnTouchListener,时刻判断ScrollView的滚动距离,一旦第一个ScrollView滚动到底部,则标识改为可向上拖动,此时开始记录滑动距离mMoveLen,根据mMoveLen重新layout两个ScrollView;同理,监听第二个ScrollView是否滚动到顶部,以往下拖动。 OK,明白了原理之后可以看代码了: **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38656929#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38656929#) <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> - <span class="keyword">package</span> com.jingchen.tbviewer; - - <span class="keyword">import</span> java.util.Timer; - <span class="keyword">import</span> java.util.TimerTask; - - <span class="keyword">import</span> android.content.Context; - <span class="keyword">import</span> android.os.Handler; - <span class="keyword">import</span> android.os.Message; - <span class="keyword">import</span> android.util.AttributeSet; - <span class="keyword">import</span> android.view.MotionEvent; - <span class="keyword">import</span> android.view.VelocityTracker; - <span class="keyword">import</span> android.view.View; - <span class="keyword">import</span> android.widget.RelativeLayout; - <span class="keyword">import</span> android.widget.ScrollView; - - <span class="comment">/**</span> - <span class="comment"> * 包含两个ScrollView的容器</span> - <span class="comment"> * </span> - <span class="comment"> * @author chenjing</span> - <span class="comment"> * </span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">class</span> ScrollViewContainer <span class="keyword">extends</span> RelativeLayout { - - <span class="comment">/**</span> - <span class="comment"> * 自动上滑</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> AUTO_UP = <span class="number"></span>; - <span class="comment">/**</span> - <span class="comment"> * 自动下滑</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> AUTO_DOWN = <span class="number">1</span>; - <span class="comment">/**</span> - <span class="comment"> * 动画完成</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> DONE = <span class="number">2</span>; - <span class="comment">/**</span> - <span class="comment"> * 动画速度</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">float</span> SPEED = <span class="number">6</span>.5f; - - <span class="keyword">private</span> <span class="keyword">boolean</span> isMeasured = <span class="keyword">false</span>; - - <span class="comment">/**</span> - <span class="comment"> * 用于计算手滑动的速度</span> - <span class="comment"> */</span> - <span class="keyword">private</span> VelocityTracker vt; - - <span class="keyword">private</span> <span class="keyword">int</span> mViewHeight; - <span class="keyword">private</span> <span class="keyword">int</span> mViewWidth; - - <span class="keyword">private</span> View topView; - <span class="keyword">private</span> View bottomView; - - <span class="keyword">private</span> <span class="keyword">boolean</span> canPullDown; - <span class="keyword">private</span> <span class="keyword">boolean</span> canPullUp; - <span class="keyword">private</span> <span class="keyword">int</span> state = DONE; - - <span class="comment">/**</span> - <span class="comment"> * 记录当前展示的是哪个view,0是topView,1是bottomView</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mCurrentViewIndex = <span class="number"></span>; - <span class="comment">/**</span> - <span class="comment"> * 手滑动距离,这个是控制布局的主要变量</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">float</span> mMoveLen; - <span class="keyword">private</span> MyTimer mTimer; - <span class="keyword">private</span> <span class="keyword">float</span> mLastY; - <span class="comment">/**</span> - <span class="comment"> * 用于控制是否变动布局的另一个条件,mEvents==0时布局可以拖拽了,mEvents==-1时可以舍弃将要到来的第一个move事件,</span> - <span class="comment"> * 这点是去除多点拖动剧变的关键</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mEvents; - - <span class="keyword">private</span> Handler handler = <span class="keyword">new</span> Handler() { - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> handleMessage(Message msg) { - <span class="keyword">if</span> (mMoveLen != <span class="number"></span>) { - <span class="keyword">if</span> (state == AUTO_UP) { - mMoveLen -= SPEED; - <span class="keyword">if</span> (mMoveLen <= -mViewHeight) { - mMoveLen = -mViewHeight; - state = DONE; - mCurrentViewIndex = <span class="number">1</span>; - } - } <span class="keyword">else</span> <span class="keyword">if</span> (state == AUTO_DOWN) { - mMoveLen += SPEED; - <span class="keyword">if</span> (mMoveLen >= <span class="number"></span>) { - mMoveLen = <span class="number"></span>; - state = DONE; - mCurrentViewIndex = <span class="number"></span>; - } - } <span class="keyword">else</span> { - mTimer.cancel(); - } - } - requestLayout(); - } - - }; - - <span class="keyword">public</span> ScrollViewContainer(Context context) { - <span class="keyword">super</span>(context); - init(); - } - - <span class="keyword">public</span> ScrollViewContainer(Context context, AttributeSet attrs) { - <span class="keyword">super</span>(context, attrs); - init(); - } - - <span class="keyword">public</span> ScrollViewContainer(Context context, AttributeSet attrs, <span class="keyword">int</span> defStyle) { - <span class="keyword">super</span>(context, attrs, defStyle); - init(); - } - - <span class="keyword">private</span> <span class="keyword">void</span> init() { - mTimer = <span class="keyword">new</span> MyTimer(handler); - } - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">boolean</span> dispatchTouchEvent(MotionEvent ev) { - <span class="keyword">switch</span> (ev.getActionMasked()) { - <span class="keyword">case</span> MotionEvent.ACTION_DOWN: - <span class="keyword">if</span> (vt == <span class="keyword">null</span>) - vt = VelocityTracker.obtain(); - <span class="keyword">else</span> - vt.clear(); - mLastY = ev.getY(); - vt.addMovement(ev); - mEvents = <span class="number"></span>; - <span class="keyword">break</span>; - <span class="keyword">case</span> MotionEvent.ACTION_POINTER_DOWN: - <span class="keyword">case</span> MotionEvent.ACTION_POINTER_UP: - <span class="comment">// 多一只手指按下或抬起时舍弃将要到来的第一个事件move,防止多点拖拽的bug</span> - <span class="keyword">break</span>; - <span class="keyword">case</span> MotionEvent.ACTION_MOVE: - vt.addMovement(ev); - <span class="keyword">if</span> (canPullUp && mCurrentViewIndex == <span class="number"></span> && mEvents == <span class="number"></span>) { - <span class="comment">// 防止上下越界</span> - <span class="keyword">if</span> (mMoveLen > <span class="number"></span>) { - mMoveLen = <span class="number"></span>; - mCurrentViewIndex = <span class="number"></span>; - } <span class="keyword">else</span> <span class="keyword">if</span> (mMoveLen < -mViewHeight) { - mMoveLen = -mViewHeight; - mCurrentViewIndex = <span class="number">1</span>; - - } - <span class="comment">// 防止事件冲突</span> - ev.setAction(MotionEvent.ACTION_CANCEL); - } - } <span class="keyword">else</span> <span class="keyword">if</span> (canPullDown && mCurrentViewIndex == <span class="number">1</span> && mEvents == <span class="number"></span>) { - <span class="comment">// 防止上下越界</span> - <span class="keyword">if</span> (mMoveLen < -mViewHeight) { - mMoveLen = -mViewHeight; - mCurrentViewIndex = <span class="number">1</span>; - } <span class="keyword">else</span> <span class="keyword">if</span> (mMoveLen > <span class="number"></span>) { - mMoveLen = <span class="number"></span>; - mCurrentViewIndex = <span class="number"></span>; - } - <span class="comment">// 防止事件冲突</span> - ev.setAction(MotionEvent.ACTION_CANCEL); - } - } <span class="keyword">else</span> - mEvents++; - mLastY = ev.getY(); - requestLayout(); - <span class="keyword">break</span>; - <span class="keyword">case</span> MotionEvent.ACTION_UP: - mLastY = ev.getY(); - vt.addMovement(ev); - vt.computeCurrentVelocity(<span class="number">700</span>); - <span class="comment">// 获取Y方向的速度</span> - <span class="keyword">float</span> mYV = vt.getYVelocity(); - <span class="keyword">if</span> (mMoveLen == <span class="number"></span> || mMoveLen == -mViewHeight) - <span class="keyword">break</span>; - <span class="keyword">if</span> (Math.abs(mYV) < <span class="number">500</span>) { - <span class="comment">// 速度小于一定值的时候当作静止释放,这时候两个View往哪移动取决于滑动的距离</span> - <span class="keyword">if</span> (mMoveLen <= -mViewHeight / <span class="number">2</span>) { - state = AUTO_UP; - } <span class="keyword">else</span> <span class="keyword">if</span> (mMoveLen > -mViewHeight / <span class="number">2</span>) { - state = AUTO_DOWN; - } - } <span class="keyword">else</span> { - <span class="comment">// 抬起手指时速度方向决定两个View往哪移动</span> - <span class="keyword">if</span> (mYV < <span class="number"></span>) - state = AUTO_UP; - <span class="keyword">else</span> - state = AUTO_DOWN; - } - mTimer.schedule(<span class="number">2</span>); - <span class="keyword">try</span> { - vt.recycle(); - } <span class="keyword">catch</span> (Exception e) { - e.printStackTrace(); - } - <span class="keyword">break</span>; - - } - <span class="keyword">super</span>.dispatchTouchEvent(ev); - <span class="keyword">return</span> <span class="keyword">true</span>; - } - - <span class="annotation">@Override</span> - <span class="keyword">protected</span> <span class="keyword">void</span> onLayout(<span class="keyword">boolean</span> changed, <span class="keyword">int</span> l, <span class="keyword">int</span> t, <span class="keyword">int</span> r, <span class="keyword">int</span> b) { - topView.layout(<span class="number"></span>, (<span class="keyword">int</span>) mMoveLen, mViewWidth, - topView.getMeasuredHeight() + (<span class="keyword">int</span>) mMoveLen); - bottomView.layout(<span class="number"></span>, topView.getMeasuredHeight() + (<span class="keyword">int</span>) mMoveLen, - mViewWidth, topView.getMeasuredHeight() + (<span class="keyword">int</span>) mMoveLen - + bottomView.getMeasuredHeight()); - } - - <span class="annotation">@Override</span> - <span class="keyword">protected</span> <span class="keyword">void</span> onMeasure(<span class="keyword">int</span> widthMeasureSpec, <span class="keyword">int</span> heightMeasureSpec) { - <span class="keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec); - <span class="keyword">if</span> (!isMeasured) { - isMeasured = <span class="keyword">true</span>; - - mViewHeight = getMeasuredHeight(); - mViewWidth = getMeasuredWidth(); - - topView = getChildAt(<span class="number"></span>); - bottomView = getChildAt(<span class="number">1</span>); - - bottomView.setOnTouchListener(bottomViewTouchListener); - topView.setOnTouchListener(topViewTouchListener); - } - } - - <span class="keyword">private</span> OnTouchListener topViewTouchListener = <span class="keyword">new</span> OnTouchListener() { - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">boolean</span> onTouch(View v, MotionEvent event) { - ScrollView sv = (ScrollView) v; - .getMeasuredHeight()) && mCurrentViewIndex == <span class="number"></span>) - canPullUp = <span class="keyword">true</span>; - <span class="keyword">else</span> - canPullUp = <span class="keyword">false</span>; - <span class="keyword">return</span> <span class="keyword">false</span>; - } - }; - <span class="keyword">private</span> OnTouchListener bottomViewTouchListener = <span class="keyword">new</span> OnTouchListener() { - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">boolean</span> onTouch(View v, MotionEvent event) { - ScrollView sv = (ScrollView) v; - <span class="keyword">if</span> (sv.getScrollY() == <span class="number"></span> && mCurrentViewIndex == <span class="number">1</span>) - canPullDown = <span class="keyword">true</span>; - <span class="keyword">else</span> - canPullDown = <span class="keyword">false</span>; - <span class="keyword">return</span> <span class="keyword">false</span>; - } - }; - - <span class="keyword">class</span> MyTimer { - <span class="keyword">private</span> Handler handler; - <span class="keyword">private</span> Timer timer; - <span class="keyword">private</span> MyTask mTask; - - <span class="keyword">public</span> MyTimer(Handler handler) { - <span class="keyword">this</span>.handler = handler; - timer = <span class="keyword">new</span> Timer(); - } - - <span class="keyword">public</span> <span class="keyword">void</span> schedule(<span class="keyword">long</span> period) { - <span class="keyword">if</span> (mTask != <span class="keyword">null</span>) { - mTask.cancel(); - mTask = <span class="keyword">null</span>; - } - mTask = <span class="keyword">new</span> MyTask(handler); - timer.schedule(mTask, <span class="number"></span>, period); - } - - <span class="keyword">public</span> <span class="keyword">void</span> cancel() { - <span class="keyword">if</span> (mTask != <span class="keyword">null</span>) { - mTask.cancel(); - mTask = <span class="keyword">null</span>; - } - } - - <span class="keyword">class</span> MyTask <span class="keyword">extends</span> TimerTask { - <span class="keyword">private</span> Handler handler; - - <span class="keyword">public</span> MyTask(Handler handler) { - <span class="keyword">this</span>.handler = handler; - } - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> run() { - handler.obtainMessage().sendToTarget(); - } - - } - } - - } 注释写的很清楚了,有几个关键点需要讲一下: ...

2015年3月4日 · 9 分钟 · 天边的星星

Android 自定义控件打造史上最简单的侧滑菜单

转载出处:http://blog.csdn.net/lmj623565791/article/details/39185641 侧滑菜单在很多应用中都会见到,最近QQ5.0侧滑还玩了点花样对于侧滑菜单,一般大家都会自定义ViewGroup,然后隐藏菜单栏,当手指滑动时,通过Scroller或者不断的改变leftMargin等实现;多少都有点复杂,完成以后还需要对滑动冲突等进行处理今天给大家带来一个简单的实现,史上最简单有点夸张,但是的确是我目前遇到过的最简单的一种实现~~~ 1、原理分析 既然是侧滑,无非就是在巴掌大的屏幕,塞入大概两巴掌大的布局,需要滑动可以出现另一个,既然这样,大家为啥不考虑使用Android提供的HorizontalScrollView呢~ 如果使用HorizontalScrollView,还需要在ACTION_DOWN , ACTION_MOVE里面去监听,判断,不断改变控件位置了么? NO!!!HorizontalScrollView本身就带了滑动的功能~~ 还需要自己的手动处理各种冲突么?NO!!!当然了,还是需要了解下事件分发机制的~~~ 2、效果图 嗯,主界面搞了QQ一张图片,左边盗用了一兄弟的布局文件罪过 谁有好看的布局、图片、图标神马的,可以给我发点,感激~ 3、布局文件 **[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39185641#)[copy](http://blog.csdn.net/lmj623565791/article/details/39185641#) <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> - <span class="tag"><</span><span class="tag-name">com.example.zhy_slidingmenu.SlidingMenu</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span> - <span class="attribute">xmlns:tools</span>=<span class="attribute-value">&#8220;http://schemas.android.com/tools&#8221;</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span> - <span class="attribute">android:scrollbars</span>=<span class="attribute-value">&#8220;none&#8221;</span> <span class="tag">></span> - - <span class="tag"><</span><span class="tag-name">LinearLayout</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span> - <span class="attribute">android:orientation</span>=<span class="attribute-value">&#8220;horizontal&#8221;</span> <span class="tag">></span> - - <span class="tag"><</span><span class="tag-name">include</span> <span class="attribute">layout</span>=<span class="attribute-value">&#8220;@layout/layout_menu&#8221;</span> <span class="tag">/></span> - - <span class="tag"><</span><span class="tag-name">LinearLayout</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;fill_parent&#8221;</span> - <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;@drawable/qq&#8221;</span> <span class="tag">></span> - <span class="tag"></</span><span class="tag-name">LinearLayout</span><span class="tag">></span> - <span class="tag"></</span><span class="tag-name">LinearLayout</span><span class="tag">></span> - - <span class="tag"></</span><span class="tag-name">com.example.zhy_slidingmenu.SlidingMenu</span><span class="tag">></span> 首先是我们的自定义View,里面一个方向水平的LinearLayout,然后就是一个是菜单的布局,一个是主布局了~ ...

2015年3月3日 · 5 分钟 · 天边的星星

Android 高仿 QQ 侧滑菜单效果 自定义控件来袭

转载出处:http://blog.csdn.net/lmj623565791/article/details/39257409 上一篇博客带大家实现了:Android 自定义控件打造史上最简单的侧滑菜单 ,有兄弟看了以后说,你这滑动菜单过时了呀~QQ5.0的效果还不错嗯,的确,上一篇也承诺过,稍微修改上一篇的代码,实现QQ5.0侧滑菜单好了,下面就开始为大家展示写一个类QQ的侧滑有多easy ~! 1、原理分析 首先对比一下我们上篇的实现距离QQ的效果还有多远: 差距还是蛮大的 区别1、QQ的内容区域会伴随菜单的出现而缩小 区别2、QQ的侧滑菜单给人的感觉是隐藏在内容的后面,而不是拖出来的感觉 区别3、QQ的侧滑菜单有一个缩放以及透明度的效果~ 那么我们如何能做到呢: 对于区别1:这个好办,我们可以在滑动的时候,不断的改变内容区域的大小;如何改变呢?我们在菜单出现的整个过程中,不断记录菜单显示的宽度与其总宽度的比值,是个从0到1的过程,然后把01转化为10.7(假设内容区域缩小至0.7);不断去缩小内容区域; 对于区别3:也比较好办,上面已经可以得到0到1的这个值了,那么缩放和透明度的动画就不在话下了; 对于区别2:我们使用的HorizontalScrollView,然后水平放置了菜单和内容,如何让菜单可以隐藏到内容的后面呢?其实也比较简单,在菜单出现的过程中,不断设置菜单的x方向的偏移量;0的时候完全隐藏,0.3的时候,隐藏x方向偏移量为0.7个宽度,类推~~~ 好了,分析完毕,那么对于这些动画用什么实现最好呢? 想都不用想,属性动画哈,如果你对属性动画不了解,可以参:Android 属性动画(Property Animation) 完全解析 (上)和Android 属性动画(Property Animation) 完全解析 (下) 2、实现 1、初步的代码 布局文件神马的,都和上一篇一模一样,这里就不重复贴代码了,不了解的,先看下上一篇; 先看一下上一篇我们已经实现的完整代码: **[java]** [view plain](http://blog.csdn.net/lmj623565791/article/details/39257409#)[copy](http://blog.csdn.net/lmj623565791/article/details/39257409#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/468874)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/468874/fork) <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> - <span class="keyword">package</span> com.example.zhy_slidingmenu; - - <span class="keyword">import</span> android.content.Context; - <span class="keyword">import</span> android.content.res.TypedArray; - <span class="keyword">import</span> android.util.AttributeSet; - <span class="keyword">import</span> android.util.TypedValue; - <span class="keyword">import</span> android.view.MotionEvent; - <span class="keyword">import</span> android.view.ViewGroup; - <span class="keyword">import</span> android.widget.HorizontalScrollView; - <span class="keyword">import</span> android.widget.LinearLayout; - - <span class="keyword">import</span> com.zhy.utils.ScreenUtils; - - <span class="keyword">public</span> <span class="keyword">class</span> SlidingMenu <span class="keyword">extends</span> HorizontalScrollView - { - <span class="comment">/**</span> - <span class="comment"> * 屏幕宽度</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mScreenWidth; - <span class="comment">/**</span> - <span class="comment"> * dp</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mMenuRightPadding; - <span class="comment">/**</span> - <span class="comment"> * 菜单的宽度</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mMenuWidth; - <span class="keyword">private</span> <span class="keyword">int</span> mHalfMenuWidth; - - <span class="keyword">private</span> <span class="keyword">boolean</span> isOpen; - - <span class="keyword">private</span> <span class="keyword">boolean</span> once; - - <span class="keyword">public</span> SlidingMenu(Context context, AttributeSet attrs) - { - <span class="keyword">this</span>(context, attrs, <span class="number"></span>); - - } - - <span class="keyword">public</span> SlidingMenu(Context context, AttributeSet attrs, <span class="keyword">int</span> defStyle) - { - <span class="keyword">super</span>(context, attrs, defStyle); - mScreenWidth = ScreenUtils.getScreenWidth(context); - - TypedArray a = context.getTheme().obtainStyledAttributes(attrs, - R.styleable.SlidingMenu, defStyle, <span class="number"></span>); - <span class="keyword">int</span> n = a.getIndexCount(); - <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < n; i++) - { - <span class="keyword">int</span> attr = a.getIndex(i); - <span class="keyword">switch</span> (attr) - { - <span class="keyword">case</span> R.styleable.SlidingMenu_rightPadding: - <span class="comment">// 默认50</span> - mMenuRightPadding = a.getDimensionPixelSize(attr, - (<span class="keyword">int</span>) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, 50f, - getResources().getDisplayMetrics()));<span class="comment">// 默认为10DP</span> - <span class="keyword">break</span>; - } - } - a.recycle(); - } - - <span class="keyword">public</span> SlidingMenu(Context context) - { - <span class="keyword">this</span>(context, <span class="keyword">null</span>, <span class="number"></span>); - } - - <span class="annotation">@Override</span> - <span class="keyword">protected</span> <span class="keyword">void</span> onMeasure(<span class="keyword">int</span> widthMeasureSpec, <span class="keyword">int</span> heightMeasureSpec) - { - <span class="comment">/**</span> - <span class="comment"> * 显示的设置一个宽度</span> - <span class="comment"> */</span> - <span class="keyword">if</span> (!once) - { - LinearLayout wrapper = (LinearLayout) getChildAt(<span class="number"></span>); - ViewGroup menu = (ViewGroup) wrapper.getChildAt(<span class="number"></span>); - ViewGroup content = (ViewGroup) wrapper.getChildAt(<span class="number">1</span>); - - mMenuWidth = mScreenWidth &#8211; mMenuRightPadding; - mHalfMenuWidth = mMenuWidth / <span class="number">2</span>; - menu.getLayoutParams().width = mMenuWidth; - content.getLayoutParams().width = mScreenWidth; - - } - <span class="keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec); - - } - - <span class="annotation">@Override</span> - <span class="keyword">protected</span> <span class="keyword">void</span> onLayout(<span class="keyword">boolean</span> changed, <span class="keyword">int</span> l, <span class="keyword">int</span> t, <span class="keyword">int</span> r, <span class="keyword">int</span> b) - { - <span class="keyword">super</span>.onLayout(changed, l, t, r, b); - <span class="keyword">if</span> (changed) - { - <span class="comment">// 将菜单隐藏</span> - <span class="keyword">this</span>.scrollTo(mMenuWidth, <span class="number"></span>); - once = <span class="keyword">true</span>; - } - } - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">boolean</span> onTouchEvent(MotionEvent ev) - { - <span class="keyword">int</span> action = ev.getAction(); - <span class="keyword">switch</span> (action) - { - <span class="comment">// Up时,进行判断,如果显示区域大于菜单宽度一半则完全显示,否则隐藏</span> - <span class="keyword">case</span> MotionEvent.ACTION_UP: - <span class="keyword">int</span> scrollX = getScrollX(); - <span class="keyword">if</span> (scrollX > mHalfMenuWidth) - { - <span class="keyword">this</span>.smoothScrollTo(mMenuWidth, <span class="number"></span>); - isOpen = <span class="keyword">false</span>; - } <span class="keyword">else</span> - { - <span class="keyword">this</span>.smoothScrollTo(<span class="number"></span>, <span class="number"></span>); - isOpen = <span class="keyword">true</span>; - } - <span class="keyword">return</span> <span class="keyword">true</span>; - } - <span class="keyword">return</span> <span class="keyword">super</span>.onTouchEvent(ev); - } - - <span class="comment">/**</span> - <span class="comment"> * 打开菜单</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">void</span> openMenu() - { - <span class="keyword">if</span> (isOpen) - <span class="keyword">return</span>; - <span class="keyword">this</span>.smoothScrollTo(<span class="number"></span>, <span class="number"></span>); - isOpen = <span class="keyword">true</span>; - } - - <span class="comment">/**</span> - <span class="comment"> * 关闭菜单</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">void</span> closeMenu() - { - <span class="keyword">if</span> (isOpen) - { - <span class="keyword">this</span>.smoothScrollTo(mMenuWidth, <span class="number"></span>); - isOpen = <span class="keyword">false</span>; - } - } - - <span class="comment">/**</span> - <span class="comment"> * 切换菜单状态</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">void</span> toggle() - { - <span class="keyword">if</span> (isOpen) - { - closeMenu(); - } <span class="keyword">else</span> - { - openMenu(); - } - } - - - - } 利用HorizontalScrollView,监听了ACTION_UP的事件,当用户抬起手指时,根据当前菜单显示的宽度值,判断是缩回还是完全展开;给用户提供了一个rightPadding属性,用于设置菜单离右屏幕的距离;以及对外提供了打开,关闭,切换的几个方法;具体的讲解看下上篇博客了; ...

2015年3月3日 · 6 分钟 · 天边的星星

Android开发实践:自定义ViewGroup的onLayout()分析

Android开发中,对于自定义View,分为两种,一种 是自定义控件(继承View类),另一种是自定义布局容器(继承ViewGroup)。如果是自定义控件,则一般需要重载两个方法,一个是 onMeasure(),用来测量控件尺寸,另一个是onDraw(),用来绘制控件的UI。而自定义布局容器,则一般需要实现/重载三个方法,一个是 onMeasure(),也是用来测量尺寸;一个是onLayout(),用来布局子控件;还有一个是dispatchDraw(),用来绘制UI。 本文主要分析自定义ViewGroup的onLayout()方法的实现。 ViewGroup 类的onLayout()函数是abstract型,继承者必须实现,由于ViewGroup的定位就是一个容器,用来盛放子控件的,所以就必须定义要以 什么的方式来盛放,比如LinearLayout就是以横向或者纵向顺序存放,而RelativeLayout则以相对位置来摆放子控件,同样,我们的自 定义ViewGroup也必须给出我们期望的布局方式,而这个定义就通过onLayout()函数来实现。 我们通过实现一个水平优先布局的视图容器来更加深入地了解onLayout()的实现吧,效果如图所示(黑色方块为子控件,白色部分为自定义布局容器)。该容器的布局方式是,首先水平方向上摆放子控件,水平方向放不下了,则另起一行继续水平摆放。 ** 1. 自定义ViewGroup的派生类** 第一步,则是自定ViewGroup的派生类,继承默认的构造函数。 1 <div class="line number2 index1 alt1"> 2 </div> <div class="line number3 index2 alt2"> 3 </div> <div class="line number4 index3 alt1"> 4 </div> <div class="line number5 index4 alt2"> 5 </div> <div class="line number6 index5 alt1"> 6 </div> <div class="line number7 index6 alt2"> 7 </div> <div class="line number8 index7 alt1"> 8 </div> <div class="line number9 index8 alt2"> 9 </div> <div class="line number10 index9 alt1"> 10 </div> <div class="line number11 index10 alt2"> 11 </div> <div class="line number12 index11 alt1"> 12 </div> <div class="line number13 index12 alt2"> 13 </div> <div class="line number14 index13 alt1"> 14 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `public` `class` `CustomViewGroup ``extends` `ViewGroup {` </div> <div class="line number2 index1 alt1"> ` ` </div> <div class="line number3 index2 alt2"> ` ``public` `CustomViewGroup(Context context) {` </div> <div class="line number4 index3 alt1"> ` ``super``(context); ` </div> <div class="line number5 index4 alt2"> ` ``}` </div> <div class="line number6 index5 alt1"> ` ` </div> <div class="line number7 index6 alt2"> ` ``public` `CustomViewGroup(Context context, AttributeSet attrs) {` </div> <div class="line number8 index7 alt1"> ` ``super``(context, attrs); ` </div> <div class="line number9 index8 alt2"> ` ``}` </div> <div class="line number10 index9 alt1"> ` ` </div> <div class="line number11 index10 alt2"> ` ``public` `CustomViewGroup(Context context, AttributeSet attrs, intdefStyle) {` </div> <div class="line number12 index11 alt1"> ` ``super``(context, attrs, defStyle);` </div> <div class="line number13 index12 alt2"> ` ``}` </div> <div class="line number14 index13 alt1"> `}` </div> </div> </td> </tr> </table> ...

2014年11月17日 · 13 分钟 · 天边的星星