Android 带你从源码的角度解析Scroller的滚动实现原理

转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17483273),请尊重他人的辛勤劳动成果,谢谢! 今天给大家讲解的是Scroller类的滚动实现原理,可能很多朋友不太了解该类是用来干嘛的,但是研究Launcher的朋友应该对他很熟悉,Scroller类是滚动的一个封装类,可以实现View的平滑滚动效果,什么是实现View的平滑滚动效果呢,举个简单的例子,一个View从在我们指定的时间内从一个位置滚动到另外一个位置,我们利用Scroller类可以实现匀速滚动,可以先加速后减速,可以先减速后加速等等效果,而不是瞬间的移动的效果,所以Scroller可以帮我们实现很多滑动的效果。 在介绍Scroller类之前,我们先去了解View的scrollBy() 和scrollTo()方法的区别,在区分这两个方法的之前,我们要先理解View 里面的两个成员变量mScrollX, mScrollY,X轴方向的偏移量和Y轴方向的偏移量,这个是一个相对距离,相对的不是屏幕的原点,而是View的左边缘,举个通俗易懂的例子,一列火车从吉安到深圳,途中经过赣州,那么原点就是赣州,偏移量就是 负的吉安到赣州的距离,大家从getScrollX()方法中的注释中就能看出答案来 **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/17483273#)[copy](http://blog.csdn.net/xiaanming/article/details/17483273#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/129807)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/129807/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="comment">/**</span> - <span class="comment"> * Return the scrolled left position of this view. This is the left edge of</span> - <span class="comment"> * the displayed part of your view. You do not need to draw any pixels</span> - <span class="comment"> * farther left, since those are outside of the frame of your view on</span> - <span class="comment"> * screen.</span> - <span class="comment"> *</span> - <span class="comment"> * @return The left edge of the displayed part of your view, in pixels.</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> getScrollX() { - <span class="keyword">return</span> mScrollX; - } 现在我们知道了向右滑动 mScrollX就为负数,向左滑动mScrollX为正数,接下来我们先来看看 scrollTo()方法的源码 ...

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

Android下拉刷新上拉加载控件,对所有View通用!

转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38868463 前面写过一篇关于下拉刷新控件的博客下拉刷新控件终结者:PullToRefreshLayout,后来看到好多人还有上拉加载更多的需求,于是就在前面下拉刷新控件的基础上进行了改进,加了上拉加载的功能。不仅如此,我已经把它改成了对所有View都通用!可以随心所欲使用这两个功能~~ 我做了一个大集合的demo,实现了ListView、GridView、ExpandableListView、ScrollView、WebView、ImageView、TextView的下拉刷新和上拉加载。后面会提供demo的下载地址。(csdn上的demo有小bug,最新代码已上传到github:https://github.com/jingchenUSTC/PullToRefreshAndLoad) 依照惯例,下面将会是一大波效果图: demo首页也是可下拉的ListView,在底下可以加入table: ListView: GridView: ExpandableListView: ScrollView: WebView: ImageView: TextView: 很不错吧?最后的ImageView和TextView是最简单的,直接在下面的接口方法里返回true。 增加上拉加载很简单,和管理下拉头一样,再多管理一个上拉头,也不费事;至于把它改成通用的就需要统一一下View的行为了,为此,我定义了这样一个接口: **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38868463#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38868463#) <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.pulltorefresh.pullableview; - - <span class="keyword">public</span> <span class="keyword">interface</span> Pullable - { - <span class="comment">/**</span> - <span class="comment"> * 判断是否可以下拉,如果不需要下拉功能可以直接return false</span> - <span class="comment"> * </span> - <span class="comment"> * @return true如果可以下拉否则返回false</span> - <span class="comment"> */</span> - <span class="keyword">boolean</span> canPullDown(); - - <span class="comment">/**</span> - <span class="comment"> * 判断是否可以上拉,如果不需要上拉功能可以直接return false</span> - <span class="comment"> * </span> - <span class="comment"> * @return true如果可以上拉否则返回false</span> - <span class="comment"> */</span> - <span class="keyword">boolean</span> canPullUp(); - } 从接口名就可以看出它是一个提供判断是否可拉的方法的接口。这个接口的两个方法,canPullDown()是判断何时可以下拉的方法,canPullUp()则是判断何时可以上拉,我在demo中的判断是滑到顶部的时候可以下拉,滑到底部的时候可以上拉。所有需要上拉和下拉的View都需要实现这个接口。后面会给出一些View的实现。先来看看改进后的自定义的布局PullToRefreshLayout,增加了一个上拉头,下拉头和上拉头之间的View是实现了Pullable接口的pullableView。相比前面的版本,这里有改动的需要注意的地方如下: ...

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

Android自定义控件实战——仿多看阅读平移翻页

转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38728119 之前自己做的一个APP需要用到翻页阅读,网上看过立体翻页效果,不过bug太多了还不兼容。看了一下多看阅读翻页是采用平移翻页的,于是就仿写了一个平移翻页的控件。效果如下: 在翻页时页面右边缘绘制了阴影,效果还不错。要实现这种平移翻页控件并不难,只需要定义一个布局管理页面就可以了。具体实现上有以下难点: 1、循环翻页,页面的重复利用。 2、在翻页时过滤掉多点触碰。 3、采用setAdapter的方式设置页面布局和数据。 下面就来一一解决这几个难点。首先看循环翻页问题,怎么样能采用较少的页面实现这种翻页呢?由于屏幕上每次只能显示一张完整的页面,翻过去的页面也看不到,所以可以把翻过去的页面拿来重复利用,不必每次都new一个页面,所以,我只用了三张页面实现循环翻页。要想重复利用页面,首先要知道页面在布局中序号和对应的层次关系,比如一个父控件的子view的序号越大就位于越上层。循环利用页面的原理图如下: 向右翻页时状态图是这样的,只用了0、1、2三张页面,页面序号为2的位于最上层,我把它隐藏在左边,所以看到的只有页面1,页面0在1下面挡着也看不到,向右翻页时,页面2被滑到屏幕中,这时候把页面0的内容替换成页面2的前一页内容,把它放到之前页面2的位置,这时,状态又回到了初始状态,又可以继续向右翻页了! 向左翻页时是这样的,初始状态还是一样,当页面1被往左翻过时,看到的是页面0,这时候页面0下面已经没有页面了,而页面2已经用不到了,这时候把页面2放到页面0下面,这时候状态又回到了初始状态,就可以继续往左翻页了。 类似于这种循环效果的实现我一直用的解决方案都是将选中的置于最中间,比如原理图中的页面1,每次翻页完成后可见的都是页面1。在滚动选择器PickerView中也是同样的方案。这就解决了页面的重复利用问题了。 解决难点2 翻页时过滤多点触碰这个问题在仿淘宝商品浏览界面中已经解决过了,就是用一个控制变量mEvents过滤掉pointer down或up后到来的第一个move事件。 解决难点3 采用adapter方式设置页面的布局和数据。这个在Android的AdapterView里用到的,但是我没有看它的adapter机制,太复杂了,我就搞了个简单的adapter,如下: PageAdapter.java: **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#) <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.pagerdemo; - - <span class="keyword">import</span> android.view.View; - - <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> PageAdapter - { - <span class="comment">/**</span> - <span class="comment"> * @return 页面view</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">abstract</span> View getView(); - - <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">int</span> getCount(); - - <span class="comment">/**</span> - <span class="comment"> * 将内容添加到view中</span> - <span class="comment"> * </span> - <span class="comment"> * @param view</span> - <span class="comment"> * 包含内容的view</span> - <span class="comment"> * @param position</span> - <span class="comment"> * 第position页</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> addContent(View view, <span class="keyword">int</span> position); - } 这是一个抽象类,getView()用于返回页面的布局,getCount()返回数据总共需要多少页,addContent(View view, int position)这个是每翻过一页后将会被调用来请求页面数据的,参数view就是页面,position是表明第几页。待会儿会在自定义布局中定义setAdapter方法设置设配器。 ...

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

Android自定义控件实战——水流波动效果的实现WaveView

转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38556891 水流波动的波形都是三角波,曲线是正余弦曲线,但是Android中没有提供绘制正余弦曲线的API,好在Path类有个绘制贝塞尔曲线的方法quadTo,绘制出来的是2阶的贝塞尔曲线,要想实现波动效果,只能用它来绘制Path曲线。待会儿再讲解2阶的贝塞尔曲线是怎么回事,先来看实现的效果: 这个波长比较短,还看不到起伏,只是荡漾,把波长拉长再看一下: 已经可以看到起伏很明显了,再拉长看一下: 这个的起伏感就比较强了。利用这个波动效果,可以用在绘制水位线的时候使用到,还可以做一个波动的进度条WaveUpProgress,比如这样: 是不是很动感? 那这样的波动效果是怎么做的呢?前面讲到的贝塞尔曲线到底是什么呢?下面一一讲解。想要用好贝塞尔曲线就得先理解它的表达式,为了形象描述,我从网上盗了些动图。 首先看1阶贝塞尔曲线的表达式: 随着t的变化,它实际是一条P0到P1的直线段: Android中Path的quadTo是3点的2阶贝塞尔曲线,那么2阶的表达式是这样的: 看起来很复杂,我把它拆分开来看: 然后再合并成这样: 看到什么了吧?如果看不出来再替换成这样: B0和B1分别是P0到P1和P1到P2的1阶贝塞尔曲线。而2阶贝塞尔曲线B就是B0到B1的1阶贝塞尔曲线。显然,它的动态图表示出来就不难理解了: 红色点的运动轨迹就是B的轨迹,这就是2阶贝塞尔曲线了。当P1位于P0和P2的垂直平分线上时,B就是开口向上或向下的抛物线了。而在WaveView中就是用的开口向上和向下的抛物线模拟水波。在Android里用Path的方法,首先path.moveTo(P0),然后path.quadTo(P1, P2),canvas.drawPath(path, paint)曲线就出来了,如果想要绘制多个贝塞尔曲线就不断的quadTo吧。 讲完贝塞尔曲线后就要开始讲水波动的效果是怎么来的了,首先要理解,机械波的传输就是通过介质的震动把波形往传输方向平移,每震动一个周期波形刚好平移一个波长,所有介质点又回到一个周期前的状态。所以要实现水波动效果只需要把波形平移就可以了。 那么WaveView的实现原理是这样的: 首先在View上根据View宽计算可以容纳几个完整波形,不够一个的算一个,然后在View的不可见处预留一个完整的波形;然后波动开始的时候将所有点同时在x方向上移动相同的距离,这样隐藏的波形就会被平移出来,当平移距离达到一个波长时,这时候将所有点的x坐标又恢复到平移前的值,这样就可以一个波形一个波形地往外传输。用草图表示如下: WaveView的原理在上图很直观的看出来了,P[2n+1],n>=0都是贝塞尔曲线的控制点,红线为水位线。 知道原理以后可以看代码了: WaveView.java: **[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38556891#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38556891#) <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.waveview; - - <span class="keyword">import</span> java.util.ArrayList; - <span class="keyword">import</span> java.util.List; - <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.graphics.Canvas; - <span class="keyword">import</span> android.graphics.Color; - <span class="keyword">import</span> android.graphics.Paint; - <span class="keyword">import</span> android.graphics.Paint.Align; - <span class="keyword">import</span> android.graphics.Paint.Style; - <span class="keyword">import</span> android.graphics.Region.Op; - <span class="keyword">import</span> android.graphics.Path; - <span class="keyword">import</span> android.graphics.RectF; - <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.View; - - <span class="comment">/**</span> - <span class="comment"> * 水流波动控件</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> WaveView <span class="keyword">extends</span> View - { - - <span class="keyword">private</span> <span class="keyword">int</span> mViewWidth; - <span class="keyword">private</span> <span class="keyword">int</span> mViewHeight; - - <span class="comment">/**</span> - <span class="comment"> * 水位线</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">float</span> mLevelLine; - - <span class="comment">/**</span> - <span class="comment"> * 波浪起伏幅度</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">float</span> mWaveHeight = <span class="number">80</span>; - <span class="comment">/**</span> - <span class="comment"> * 波长</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">float</span> mWaveWidth = <span class="number">200</span>; - <span class="comment">/**</span> - <span class="comment"> * 被隐藏的最左边的波形</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">float</span> mLeftSide; - - <span class="keyword">private</span> <span class="keyword">float</span> mMoveLen; - <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">1</span>.7f; - - <span class="keyword">private</span> List<Point> mPointsList; - <span class="keyword">private</span> Paint mPaint; - <span class="keyword">private</span> Paint mTextPaint; - <span class="keyword">private</span> Path mWavePath; - <span class="keyword">private</span> <span class="keyword">boolean</span> isMeasured = <span class="keyword">false</span>; - - <span class="keyword">private</span> Timer timer; - <span class="keyword">private</span> MyTimerTask mTask; - Handler updateHandler = <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="comment">// 记录平移总位移</span> - mMoveLen += SPEED; - <span class="comment">// 水位上升</span> - mLevelLine -= <span class="number"></span>.1f; - <span class="keyword">if</span> (mLevelLine < <span class="number"></span>) - mLevelLine = <span class="number"></span>; - mLeftSide += SPEED; - <span class="comment">// 波形平移</span> - <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < mPointsList.size(); i++) - { - mPointsList.get(i).setX(mPointsList.get(i).getX() + SPEED); - <span class="keyword">switch</span> (i % <span class="number">4</span>) - { - <span class="keyword">case</span> <span class="number"></span>: - <span class="keyword">case</span> <span class="number">2</span>: - mPointsList.get(i).setY(mLevelLine); - <span class="keyword">break</span>; - <span class="keyword">case</span> <span class="number">1</span>: - mPointsList.get(i).setY(mLevelLine + mWaveHeight); - <span class="keyword">break</span>; - <span class="keyword">case</span> <span class="number">3</span>: - mPointsList.get(i).setY(mLevelLine &#8211; mWaveHeight); - <span class="keyword">break</span>; - } - } - <span class="keyword">if</span> (mMoveLen >= mWaveWidth) - { - <span class="comment">// 波形平移超过一个完整波形后复位</span> - mMoveLen = <span class="number"></span>; - resetPoints(); - } - invalidate(); - } - - }; - - <span class="comment">/**</span> - <span class="comment"> * 所有点的x坐标都还原到初始状态,也就是一个周期前的状态</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">void</span> resetPoints() - { - mLeftSide = -mWaveWidth; - <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < mPointsList.size(); i++) - { - mPointsList.get(i).setX(i * mWaveWidth / <span class="number">4</span> &#8211; mWaveWidth); - } - } - - <span class="keyword">public</span> WaveView(Context context) - { - <span class="keyword">super</span>(context); - init(); - } - - <span class="keyword">public</span> WaveView(Context context, AttributeSet attrs) - { - <span class="keyword">super</span>(context, attrs); - init(); - } - - <span class="keyword">public</span> WaveView(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() - { - mPointsList = <span class="keyword">new</span> ArrayList<Point>(); - timer = <span class="keyword">new</span> Timer(); - - mPaint = <span class="keyword">new</span> Paint(); - mPaint.setAntiAlias(<span class="keyword">true</span>); - mPaint.setStyle(Style.FILL); - mPaint.setColor(Color.BLUE); - - mTextPaint = <span class="keyword">new</span> Paint(); - mTextPaint.setColor(Color.WHITE); - mTextPaint.setTextAlign(Align.CENTER); - mTextPaint.setTextSize(<span class="number">30</span>); - - mWavePath = <span class="keyword">new</span> Path(); - } - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onWindowFocusChanged(<span class="keyword">boolean</span> hasWindowFocus) - { - <span class="keyword">super</span>.onWindowFocusChanged(hasWindowFocus); - <span class="comment">// 开始波动</span> - start(); - } - - <span class="keyword">private</span> <span class="keyword">void</span> start() - { - <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> MyTimerTask(updateHandler); - timer.schedule(mTask, <span class="number"></span>, <span class="number">10</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="keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec); - <span class="keyword">if</span> (!isMeasured) - { - isMeasured = <span class="keyword">true</span>; - mViewHeight = getMeasuredHeight(); - mViewWidth = getMeasuredWidth(); - <span class="comment">// 水位线从最底下开始上升</span> - mLevelLine = mViewHeight; - <span class="comment">// 根据View宽度计算波形峰值</span> - mWaveHeight = mViewWidth / <span class="number">2</span>.5f; - <span class="comment">// 波长等于四倍View宽度也就是View中只能看到四分之一个波形,这样可以使起伏更明显</span> - mWaveWidth = mViewWidth * <span class="number">4</span>; - <span class="comment">// 左边隐藏的距离预留一个波形</span> - mLeftSide = -mWaveWidth; - <span class="comment">// 这里计算在可见的View宽度中能容纳几个波形,注意n上取整</span> - <span class="keyword">int</span> n = (<span class="keyword">int</span>) Math.round(mViewWidth / mWaveWidth + <span class="number">0.5</span>); - <span class="comment">// n个波形需要4n+1个点,但是我们要预留一个波形在左边隐藏区域,所以需要4n+5个点</span> - <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < (<span class="number">4</span> * n + <span class="number">5</span>); i++) - { - <span class="comment">// 从P0开始初始化到P4n+4,总共4n+5个点</span> - <span class="keyword">float</span> x = i * mWaveWidth / <span class="number">4</span> &#8211; mWaveWidth; - <span class="keyword">float</span> y = <span class="number"></span>; - <span class="keyword">switch</span> (i % <span class="number">4</span>) - { - <span class="keyword">case</span> <span class="number"></span>: - <span class="keyword">case</span> <span class="number">2</span>: - <span class="comment">// 零点位于水位线上</span> - y = mLevelLine; - <span class="keyword">break</span>; - <span class="keyword">case</span> <span class="number">1</span>: - <span class="comment">// 往下波动的控制点</span> - y = mLevelLine + mWaveHeight; - <span class="keyword">break</span>; - <span class="keyword">case</span> <span class="number">3</span>: - <span class="comment">// 往上波动的控制点</span> - y = mLevelLine &#8211; mWaveHeight; - <span class="keyword">break</span>; - } - mPointsList.add(<span class="keyword">new</span> Point(x, y)); - } - } - } - - <span class="annotation">@Override</span> - <span class="keyword">protected</span> <span class="keyword">void</span> onDraw(Canvas canvas) - { - - mWavePath.reset(); - <span class="keyword">int</span> i = <span class="number"></span>; - mWavePath.moveTo(mPointsList.get(<span class="number"></span>).getX(), mPointsList.get(<span class="number"></span>).getY()); - <span class="keyword">for</span> (; i < mPointsList.size() &#8211; <span class="number">2</span>; i = i + <span class="number">2</span>) - { - mWavePath.quadTo(mPointsList.get(i + <span class="number">1</span>).getX(), - mPointsList.get(i + <span class="number">1</span>).getY(), mPointsList.get(i + <span class="number">2</span>) - .getX(), mPointsList.get(i + <span class="number">2</span>).getY()); - } - mWavePath.lineTo(mPointsList.get(i).getX(), mViewHeight); - mWavePath.lineTo(mLeftSide, mViewHeight); - mWavePath.close(); - - <span class="comment">// mPaint的Style是FILL,会填充整个Path区域</span> - canvas.drawPath(mWavePath, mPaint); - <span class="comment">// 绘制百分比</span> - canvas.drawText(<span class="string">&#8220;&#8221;</span> + ((<span class="keyword">int</span>) ((<span class="number">1</span> &#8211; mLevelLine / mViewHeight) * <span class="number">100</span>)) - + <span class="string">&#8220;%&#8221;</span>, mViewWidth / <span class="number">2</span>, mLevelLine + mWaveHeight - + (mViewHeight &#8211; mLevelLine &#8211; mWaveHeight) / <span class="number">2</span>, mTextPaint); - } - - <span class="keyword">class</span> MyTimerTask <span class="keyword">extends</span> TimerTask - { - Handler handler; - - <span class="keyword">public</span> MyTimerTask(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.sendMessage(handler.obtainMessage()); - } - - } - - <span class="keyword">class</span> Point - { - <span class="keyword">private</span> <span class="keyword">float</span> x; - <span class="keyword">private</span> <span class="keyword">float</span> y; - - <span class="keyword">public</span> <span class="keyword">float</span> getX() - { - <span class="keyword">return</span> x; - } - - <span class="keyword">public</span> <span class="keyword">void</span> setX(<span class="keyword">float</span> x) - { - <span class="keyword">this</span>.x = x; - } - - <span class="keyword">public</span> <span class="keyword">float</span> getY() - { - <span class="keyword">return</span> y; - } - - <span class="keyword">public</span> <span class="keyword">void</span> setY(<span class="keyword">float</span> y) - { - <span class="keyword">this</span>.y = y; - } - - <span class="keyword">public</span> Point(<span class="keyword">float</span> x, <span class="keyword">float</span> y) - { - <span class="keyword">this</span>.x = x; - <span class="keyword">this</span>.y = y; - } - - } - - } 代码中注释写的很多,不难看懂。 ...

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

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 滑动置顶标题的实现

滑动置顶标题在QQ中的好友列表、Android的通讯录中可以见到,用户在滑动的时候可以随时看到当前的内容的标题。 这个效果的实现,思路是在Android的Listview的顶部动态的生成一个与标题等高等宽的View,并且实时监听Listview滑动的状态,当Listview滑动到第一项和第二项的标题不一致的时候,动态的重画View,让它有一种向上滑动的效果,当完全滑出以后再重画生成新的标题。 &nbsp; 话不多说,上干货 - 下载:http://www.etongwl.com/images/2015/03/b69c13c0-75c3-3160-97c8-8691ddfe9501.zip 转自:http://ygydaiaq-gmail-com.iteye.com/blog/1778844

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

Android SurfaceTexture和GLSurfaceView做Camera预览

GLSurfaceView是 OpenGL中的一个类,也是可以预览Camera的,而且在预览Camera上有其独到之处。独到之处在哪?当使用Surfaceview无能为力、痛 不欲生时就只有使用GLSurfaceView了,它能够真正做到让Camera的数据和显示分离,所以搞明白了这个,像Camera只开预览不显示这都 是小菜,妥妥的。Android4.0的自带Camera源码是用SurfaceView预览的,但到了4.2就换成了GLSurfaceView来预 览。如今到了4.4又用了自家的TextureView,所以从中可以窥探出新增TextureView的用意。 虽 说Android4.2的Camera源码是用GLSurfaceView预览的,但是进行了大量的封装又封装的,由于是OpenGL小白,真是看的不知 所云。俺滴要求不高,只想弄个可拍照的摸清GLSurfaceView在预览Camera上的使用流程。经过一番百度一无所获,后来翻出去Google一 大圈也没发现可用的。倒是很多人都在用GLSurfaceView和Surfaceview同时预览Camera,Surfaceview用来预览数据, 在上面又铺了一层GLSurfaceView绘制一些信息。无奈自己摸索,整出来的是能拍照也能得到数据,但是界面上不是一块白板就是一块黑板啥都不显 示。后来在stackoverflow终于找到了一个可用的链接,哈哈,苍天啊,终于柳暗花明了!参考此链接,自己又改改摸索了一天才彻底搞定。之所以费这么多时间是不明白OpenGL ES2.0的绘制基本流程,跟简单的OpenGL的绘制还是稍有区别。下面上源码: 一、CameraGLSurfaceView.java 此类继承GLSurfaceView,并实现了两个接口 **[java]** [view plain](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[copy](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[print](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[?](http://blog.csdn.net/yanzi1225627/article/details/33339965#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/402612)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/402612/fork) <div> </div> <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="24" height="13" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> - <span style=<span class="string">&#8220;font-family:Comic Sans MS;font-size:18px;&#8221;</span>><span class="keyword">package</span> org.yanzi.camera.preview; - - <span class="keyword">import</span> javax.microedition.khronos.egl.EGLConfig; - <span class="keyword">import</span> javax.microedition.khronos.opengles.GL10; - - <span class="keyword">import</span> org.yanzi.camera.CameraInterface; - - <span class="keyword">import</span> android.content.Context; - <span class="keyword">import</span> android.graphics.SurfaceTexture; - <span class="keyword">import</span> android.opengl.GLES11Ext; - <span class="keyword">import</span> android.opengl.GLES20; - <span class="keyword">import</span> android.opengl.GLSurfaceView; - <span class="keyword">import</span> android.opengl.GLSurfaceView.Renderer; - <span class="keyword">import</span> android.util.AttributeSet; - <span class="keyword">import</span> android.util.Log; - - <span class="keyword">public</span> <span class="keyword">class</span> CameraGLSurfaceView <span class="keyword">extends</span> GLSurfaceView <span class="keyword">implements</span> Renderer, SurfaceTexture.OnFrameAvailableListener { - <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">&#8220;yanzi&#8221;</span>; - Context mContext; - SurfaceTexture mSurface; - <span class="keyword">int</span> mTextureID = &#8211;<span class="number">1</span>; - DirectDrawer mDirectDrawer; - <span class="keyword">public</span> CameraGLSurfaceView(Context context, AttributeSet attrs) { - <span class="keyword">super</span>(context, attrs); - <span class="comment">// TODO Auto-generated constructor stub</span> - mContext = context; - setEGLContextClientVersion(<span class="number">2</span>); - setRenderer(<span class="keyword">this</span>); - setRenderMode(RENDERMODE_WHEN_DIRTY); - } - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onSurfaceCreated(GL10 gl, EGLConfig config) { - <span class="comment">// TODO Auto-generated method stub</span> - Log.i(TAG, <span class="string">&#8220;onSurfaceCreated&#8230;&#8221;</span>); - mTextureID = createTextureID(); - mSurface = <span class="keyword">new</span> SurfaceTexture(mTextureID); - mSurface.setOnFrameAvailableListener(<span class="keyword">this</span>); - mDirectDrawer = <span class="keyword">new</span> DirectDrawer(mTextureID); - CameraInterface.getInstance().doOpenCamera(<span class="keyword">null</span>); - - } - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onSurfaceChanged(GL10 gl, <span class="keyword">int</span> width, <span class="keyword">int</span> height) { - <span class="comment">// TODO Auto-generated method stub</span> - Log.i(TAG, <span class="string">&#8220;onSurfaceChanged&#8230;&#8221;</span>); - GLES20.glViewport(<span class="number"></span>, <span class="number"></span>, width, height); - <span class="keyword">if</span>(!CameraInterface.getInstance().isPreviewing()){ - CameraInterface.getInstance().doStartPreview(mSurface, <span class="number">1</span>.33f); - } - - - } - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onDrawFrame(GL10 gl) { - <span class="comment">// TODO Auto-generated method stub</span> - Log.i(TAG, <span class="string">&#8220;onDrawFrame&#8230;&#8221;</span>); - GLES20.glClearColor(<span class="number">1</span>.0f, <span class="number">1</span>.0f, <span class="number">1</span>.0f, <span class="number">1</span>.0f); - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); - mSurface.updateTexImage(); - <span class="keyword">float</span>[] mtx = <span class="keyword">new</span> <span class="keyword">float</span>[<span class="number">16</span>]; - mSurface.getTransformMatrix(mtx); - mDirectDrawer.draw(mtx); - } - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onPause() { - <span class="comment">// TODO Auto-generated method stub</span> - <span class="keyword">super</span>.onPause(); - CameraInterface.getInstance().doStopCamera(); - } - <span class="keyword">private</span> <span class="keyword">int</span> createTextureID() - { - <span class="keyword">int</span>[] texture = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">1</span>]; - - GLES20.glGenTextures(<span class="number">1</span>, texture, <span class="number"></span>); - GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[<span class="number"></span>]); - GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR); - GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, - GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); - - <span class="keyword">return</span> texture[<span class="number"></span>]; - } - <span class="keyword">public</span> SurfaceTexture _getSurfaceTexture(){ - <span class="keyword">return</span> mSurface; - } - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onFrameAvailable(SurfaceTexture surfaceTexture) { - <span class="comment">// TODO Auto-generated method stub</span> - Log.i(TAG, <span class="string">&#8220;onFrameAvailable&#8230;&#8221;</span>); - <span class="keyword">this</span>.requestRender(); - } - - } - </span> 关于这个类进行简单说明: ...

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

android 滑动菜单SlidingMenu的实现

github上类似项目 https://github.com/jfeinstein10/SlidingMenu https://github.com/yueyueniao2012/SlidingMenu *转自:* [http://blog.csdn.net/jj120522/article/details/8075249](http://blog.csdn.net/jj120522/article/details/8075249?utm_source=tuicool) 首先我们看下面视图: ![](http://img1.tuicool.com/yyqeQv.png) ![](http://img0.tuicool.com/mYVFFr.png) 这种效果大家都不陌生,网上好多都说是仿人人网的,估计人家牛逼出来的早吧,我也参考了一一些例子,实现起来有三种方法,我下面简单介绍下: 方法一: 其实就是对GestureDetector手势的应用及布局文件的设计 . 布局文件main.xml 采用RelativeLayout布局. ``` <?xml version=“1.0” encoding=“utf-8”?> <RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android" android:layout_width=“fill_parent” android:layout_height=“fill_parent” android:orientation=“vertical” > <span class="tag">&lt;<span class="title">LinearLayout android:id=”@+id/layout_right" android:layout_width=“fill_parent” android:layout_height=“fill_parent” android:layout_marginLeft=“50dp” android:orientation=“vertical” > <span class="tag">&lt;<span class="title">AbsoluteLayout android:layout_width=“fill_parent” android:layout_height=“wrap_content” android:background="@color/grey21" android:padding=“10dp” > <span class="tag">&lt;<span class="title">TextView android:layout_width=“wrap_content” android:layout_height=“wrap_content” android:text=“设置” android:textColor="@android:color/background_light" android:textSize=“20sp” /> </AbsoluteLayout> <span class="tag">&lt;<span class="title">ListView android:id="@+id/lv_set" android:layout_width=“fill_parent” android:layout_height=“fill_parent” android:layout_weight=“1” > </ListView> </LinearLayout> <span class="tag">&lt;<span class="title">LinearLayout android:id="@+id/layout_left" android:layout_width=“fill_parent” android:layout_height=“fill_parent” android:background="@color/white" android:orientation=“vertical” > <span class="tag">&lt;<span class="title">RelativeLayout android:layout_width=“fill_parent” android:layout_height=“wrap_content” android:background="@drawable/nav_bg" > <span class="tag">&lt;<span class="title">ImageView android:id="@+id/iv_set" android:layout_width=“wrap_content” android:layout_height=“wrap_content” android:layout_alignParentRight=“true” android:layout_alignParentTop=“true” android:src="@drawable/nav_setting" /> <span class="tag">&lt;<span class="title">TextView android:layout_width=“wrap_content” android:layout_height=“wrap_content” android:layout_centerInParent=“true” android:text=“我” android:textColor="@android:color/background_light" android:textSize=“20sp” /> </RelativeLayout> ...

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

Android DrawerLayout 高仿QQ5.2双向侧滑菜单

转载出处:http://blog.csdn.net/lmj623565791/article/details/41531475 1、概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ,恰逢QQ5.2又加了一个右侧菜单,刚好看了下DrawerLayout,一方面官方的东西,我都比较感兴趣;另一方面,这玩意用起来的确方便,于是简单写了个demo,高仿QQ5.2双向侧滑,分享给大家。 首先看看效果图: DrawerLayout用起来真的很方便,下面一起看看用法~ 2、DrawerLayout的使用 直接将DrawerLayout作为根布局,然后其内部第一个View为内容区域,第二个View为左侧菜单,第三个View为右侧侧滑菜单,当前第三个是可选的。 第一个View的宽高应当设置为match_parent,当然了,这也理所当然。 第二、三个View需要设置android:layout_gravity=”left”,和android:layout_gravity=”right”且一搬高度设置为match_parent,宽度为固定值,即侧滑菜单的宽度。 按照上面的描述写个布局文件,然后设置给Activity就添加好了左右侧滑了,是不是很简单~~~ 比如我们的布局文件: **[html]** [view plain](http://blog.csdn.net/lmj623565791/article/details/41531475#)[copy](http://blog.csdn.net/lmj623565791/article/details/41531475#) <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">android.support.v4.widget.DrawerLayout</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:id</span>=<span class="attribute-value">&#8220;@+id/id_drawerLayout&#8221;</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> - <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;@drawable/img_frame_background&#8221;</span> <span class="tag">></span> - - <span class="tag"><</span><span class="tag-name">RelativeLayout</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_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">Button</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;40dp&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;30dp&#8221;</span> - <span class="attribute">android:layout_marginTop</span>=<span class="attribute-value">&#8220;10dp&#8221;</span> - <span class="attribute">android:layout_alignParentRight</span>=<span class="attribute-value">&#8220;true&#8221;</span> - <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;@drawable/youce&#8221;</span> - <span class="attribute">android:onClick</span>=<span class="attribute-value">&#8220;OpenRightMenu&#8221;</span> <span class="tag">/></span> - <span class="tag"></</span><span class="tag-name">RelativeLayout</span><span class="tag">></span> - - <span class="tag"><</span><span class="tag-name">fragment</span> - <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/id_left_menu&#8221;</span> - <span class="attribute">android:name</span>=<span class="attribute-value">&#8220;com.zhy.demo_zhy_17_drawerlayout.MenuLeftFragment&#8221;</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;200dp&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> - <span class="attribute">android:layout_gravity</span>=<span class="attribute-value">&#8220;left&#8221;</span> - <span class="attribute">android:tag</span>=<span class="attribute-value">&#8220;LEFT&#8221;</span> <span class="tag">/></span> - - <span class="tag"><</span><span class="tag-name">fragment</span> - <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/id_right_menu&#8221;</span> - <span class="attribute">android:name</span>=<span class="attribute-value">&#8220;com.zhy.demo_zhy_17_drawerlayout.MenuRightFragment&#8221;</span> - <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;100dp&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> - <span class="attribute">android:layout_gravity</span>=<span class="attribute-value">&#8220;right&#8221;</span> - <span class="attribute">android:tag</span>=<span class="attribute-value">&#8220;RIGHT&#8221;</span> <span class="tag">/></span> - - <span class="tag"></</span><span class="tag-name">android.support.v4.widget.DrawerLayout</span><span class="tag">></span> 这里我们的主内容区域为RelativeLayout ...

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

ym——Android仿QQ5.0侧滑菜单ResideMenu源码分析

AndroidResideMenu ![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091421122.gif) 先看看如何使用: 把项目源码下载下来导入工程,可以看到 ![](http://www.2cto.com/uploadfile/Collfiles/20140911/20140911091422123.jpg) ResideMenu为引用工程,再看看如何使用这个引用工程来构建出ResideMenu, 1.先new一个ResideMenu对象 [?](http://www.2cto.com/kf/201409/332224.html#) <table border="0" cellspacing="0" cellpadding="0"> <tr> <td class="gutter"> <div class="line number1 index0 alt2"> 1 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `resideMenu = ``new` `ResideMenu(``this``);` </div> </div> </td> </tr> </table> 2.设置它的背景图片 [?](http://www.2cto.com/kf/201409/332224.html#) <table border="0" cellspacing="0" cellpadding="0"> <tr> <td class="gutter"> <div class="line number1 index0 alt2"> 1 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `resideMenu.setBackground(R.drawable.menu_background);` </div> </div> </td> </tr> </table> 3.绑定当前Activity ...

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