Android 向右滑动销毁(finish)Activity, 随着手势的滑动而滑动的效果

转载(http://blog.csdn.net/xiaanming/article/details/20934541) 今天给大家带来一个向右滑动销毁Activity的效果,Activtiy随着手指的移动而移动,该效果在Android应用中还是比较少见的,在IOS中就比较常见了,例如“网易新闻” ,”美食杰” , “淘宝”等应用采用此效果,而Android应用中“知乎”采用的也是这种滑动切换Activity的效果, 不过我发现“淘宝”并没有随着手势的移动而移动,只是捕捉到滑动手势,然后产生平滑切换界面的动画效果,这个在Android中还是很好实现的, 网上很多滑动切换Activity的Demo貌似都是这种效果的吧,如果要实现类似“网易新闻”的随手势的滑动而滑动,似乎就要复杂一些了,我之前在IOS中看到”网易新闻”的这种效果就很感兴趣,然后群里也有朋友问我怎么实现类似“知乎”这个应用的滑动切换的效果,我也特意去下了一个“知乎”,在之前的实现中我遇到了一些瓶颈,没有实现出来就搁置了在那里,今天无意中看到给Activity设置透明的背景,于是乎我恍然大悟,真是灵感来源于瞬间,不能强求啊,然后自己就将此效果实现了出来,给大家分享一下,希望给有此需求的你一点点帮助。 不知道大家对Scroller这个类以及View的scrollBy() 和scrollTo()的使用熟悉不?我之前介绍了Scroller类的滑动实现原理Android 带你从源码的角度解析Scroller的滚动实现原理,在那里面也介绍了scrollBy() 和scrollTo()方法,不明白的同学可以去看看,这对实现此效果有很大的帮助,了解scrollBy() 和scrollTo()的朋友应该知道,如果想对某个View(例如Button)就行滚动,我们直接调用该View(Button)的scrollBy()方法,并不是该View(Button)进行滚动,而是该View里面的内容(Button上面的文字)进行滚动,所以我们假如要让View整体滚动就需要对其View的父布局调用scrollBy()方法,回到这篇文章来,假如我们想要对一个Activity进行滚动,我们就需求对这个Activity布局文件的顶层布局的父布局进行滚动 例如下面的XML布局文件 **[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/20934541#)[copy](http://blog.csdn.net/xiaanming/article/details/20934541#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/232806)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/232806/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="tag"><</span><span class="tag-name">LinearLayout</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;match_parent&#8221;</span> - <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> - <span class="attribute">android:gravity</span>=<span class="attribute-value">&#8220;center&#8221;</span> - <span class="attribute">android:orientation</span>=<span class="attribute-value">&#8220;vertical&#8221;</span> <span class="tag">></span> - - - <span class="tag"></</span><span class="tag-name">LinearLayout</span><span class="tag">></span> 如果我们对LinearLayout进行滚动,并不能实现我们想要的效果,而只能对LinearLayout里面的内容或者说是子View进行滚动,所以我们需要获取利用LinearLayout的getParent()方法获取父布局,其实Android系统会对我们的布局文件的最外层套一个FrameLayout,所以我们其实就是对FrameLayout进行滚动就行了 了解了实现的原理之后,我们就来编写代码吧,首先新建一个android工程,取名SildingFinish ...

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

Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果

转载(http://blog.csdn.net/xiaanming/article/details/20481185) 大家好!过完年回来到现在差不多一个月没写文章了,一是觉得不知道写哪些方面的文章,没有好的题材来写,二是因为自己的一些私事给耽误了,所以过完年的第一篇文章到现在才发表出来,2014年我还是会继续在CSDN上面更新我的博客,欢迎大家关注一下,今天这篇文章主要的是介绍下开源库StickyGridHeaders的使用,StickyGridHeaders是一个自定义GridView带sections和headers的Android库,sections就是GridView item之间的分隔,headers就是固定在GridView顶部的标题,类似一些Android手机联系人的效果,StickyGridHeaders的介绍在https://github.com/TonicArtos/StickyGridHeaders,与此对应也有一个相同效果的自定义ListView带sections和headers的开源库https://github.com/emilsjolander/StickyListHeaders,大家有兴趣的可以去看下,我这里介绍的是StickyGridHeaders的使用,我在Android应用方面看到使用StickyGridHeaders的不是很多,而是在Iphone上看到相册采用的是这种效果,于是我就使用StickyGridHeaders来仿照Iphone按照日期分隔显示本地图片 我们先新建一个Android项目StickyHeaderGridView,去https://github.com/TonicArtos/StickyGridHeaders下载开源库,为了方便浏览源码我直接将源码拷到我的工程中了 com.tonicartos.widget.stickygridheaders这个包就是我放StickyGridHeaders开源库的源码,com.example.stickyheadergridview这个包是我实现此功能的代码,类看起来还蛮多的,下面我就一一来介绍了 GridItem用来封装StickyGridHeadersGridView 每个Item的数据,里面有本地图片的路径,图片加入手机系统的时间和headerId **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/20481185#)[copy](http://blog.csdn.net/xiaanming/article/details/20481185#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/220204)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/220204/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.stickyheadergridview; - <span class="comment">/**</span> - <span class="comment"> * @blog http://blog.csdn.net/xiaanming</span> - <span class="comment"> * </span> - <span class="comment"> * @author xiaanming</span> - <span class="comment"> *</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">class</span> GridItem { - <span class="comment">/**</span> - <span class="comment"> * 图片的路径</span> - <span class="comment"> */</span> - <span class="keyword">private</span> String path; - <span class="comment">/**</span> - <span class="comment"> * 图片加入手机中的时间,只取了年月日</span> - <span class="comment"> */</span> - <span class="keyword">private</span> String time; - <span class="comment">/**</span> - <span class="comment"> * 每个Item对应的HeaderId</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> headerId; - - <span class="keyword">public</span> GridItem(String path, String time) { - <span class="keyword">super</span>(); - <span class="keyword">this</span>.path = path; - <span class="keyword">this</span>.time = time; - } - - <span class="keyword">public</span> String getPath() { - <span class="keyword">return</span> path; - } - <span class="keyword">public</span> <span class="keyword">void</span> setPath(String path) { - <span class="keyword">this</span>.path = path; - } - <span class="keyword">public</span> String getTime() { - <span class="keyword">return</span> time; - } - <span class="keyword">public</span> <span class="keyword">void</span> setTime(String time) { - <span class="keyword">this</span>.time = time; - } - - <span class="keyword">public</span> <span class="keyword">int</span> getHeaderId() { - <span class="keyword">return</span> headerId; - } - - <span class="keyword">public</span> <span class="keyword">void</span> setHeaderId(<span class="keyword">int</span> headerId) { - <span class="keyword">this</span>.headerId = headerId; - } - - - } 图片的路径path和图片加入的时间time 我们直接可以通过ContentProvider获取,但是headerId需要我们根据逻辑来生成。 ...

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

Android 使用ContentProvider扫描手机中的图片,仿微信显示本地图片效果

转载:http://blog.csdn.net/xiaanming/article/details/18730223 写这篇文章之前,先简单说几句,首先是先恭喜下自己获得了2013年的博客之星称号,很意外也很开心,自己是从2013年开始写博客,那时候也不知道怎么写,我从小就不喜欢写日记,作文什么的,所以刚开始都是贴代码,也没有人看,后面慢慢的,写的文章被推荐博客首页和CSDN首页(这里也要小小的感谢下小编MM),访问量逐渐的多了起来,有更多的人看我的文章,这也使自己有了继续写文章的动力,也希望我写的东西对大家有点帮助吧,在2014年我会继续在CSDN上面写博客,然后是感谢博客之星给我投票支持我的朋友们,谢谢你们支持我的每一票,最后就是2014春节马上就到了,提前祝福大家新年快乐,工作顺利,事事顺心! 回到主题,之前群里面有朋友问我,有没有关于本地图片选择的Demo,类似微信的效果,他说网上没有这方面的Demo,问我能不能写一篇关于这个效果的Demo,于是我研究了下微信的本地图片选择的Demo,自己仿照的写了下分享给大家,希望对以后有这样子需求的朋友有一点帮助吧,主要使用的是ContentProvider扫描手机中的图片,并用GridView将图片显示出来,关于GridView和ListView显示图片的问题,一直是一个很头疼的问题,因为我们手机的内存有限,手机给每个应用程序分配的内存也有限,所以图片多的情况下很容易伴随着OOM的发生,不过现在也有很多的开源的图片显示框架,对显示很多图片进行了优化,大家有兴趣的可以去了解了解,今天我的这篇文章使用的是LruCache这个类(之前写了一篇使用LruCache加载网络图片的Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅)以及对图片进行相对应的裁剪,这样也可以尽量的避免OOM的发生,我们先看下微信的效果吧 接下来我们就来实现这些效果吧,首先我们新建一个项目,取名ImageScan 首先我们先看第一个界面吧,使用将手机中的图片扫描出来,然后根据图片的所在的文件夹将其分类出来,并显示所在文件夹里面的一张图片和文件夹中图片个数,我们根据界面元素(文件夹名, 文件夹图片个数,文件夹中的一张图片)使用一个实体对象ImageBean来封装这三个属性 **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18730223#)[copy](http://blog.csdn.net/xiaanming/article/details/18730223#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/169891)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/169891/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.imagescan; - - <span class="comment">/**</span> - <span class="comment"> * GridView的每个item的数据对象</span> - <span class="comment"> * </span> - <span class="comment"> * @author len</span> - <span class="comment"> *</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">class</span> ImageBean{ - <span class="comment">/**</span> - <span class="comment"> * 文件夹的第一张图片路径</span> - <span class="comment"> */</span> - <span class="keyword">private</span> String topImagePath; - <span class="comment">/**</span> - <span class="comment"> * 文件夹名</span> - <span class="comment"> */</span> - <span class="keyword">private</span> String folderName; - <span class="comment">/**</span> - <span class="comment"> * 文件夹中的图片数</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> imageCounts; - - <span class="keyword">public</span> String getTopImagePath() { - <span class="keyword">return</span> topImagePath; - } - <span class="keyword">public</span> <span class="keyword">void</span> setTopImagePath(String topImagePath) { - <span class="keyword">this</span>.topImagePath = topImagePath; - } - <span class="keyword">public</span> String getFolderName() { - <span class="keyword">return</span> folderName; - } - <span class="keyword">public</span> <span class="keyword">void</span> setFolderName(String folderName) { - <span class="keyword">this</span>.folderName = folderName; - } - <span class="keyword">public</span> <span class="keyword">int</span> getImageCounts() { - <span class="keyword">return</span> imageCounts; - } - <span class="keyword">public</span> <span class="keyword">void</span> setImageCounts(<span class="keyword">int</span> imageCounts) { - <span class="keyword">this</span>.imageCounts = imageCounts; - } - - } 接下来就是主界面的布局啦,上面的导航栏我没有加进去,只有下面的GridView,所以说主界面布局中只有一个GridView ...

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

Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果

转载(http://blog.csdn.net/xiaanming/article/details/18311877) 今天还是给大家带来自定义控件的编写,自定义一个ListView的左右滑动删除Item的效果,这个效果之前已经实现过了,有兴趣的可以看下Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果,之前使用的是滑动类Scroller来实现的,但是看了下通知栏的左右滑动删除效果,确实很棒,当我们滑动Item超过一半的时候,item的透明度就变成了0,我们就知道抬起手指的时候item就被删除了,当item的透明度不为0的时候,我们抬起手指Item会回到起始位置,这样我们就知道拖动到什么位置item会删除,什么位置Item不删除,用户体验更好了,还有一个效果,就是我们滑动删除了item的时候,ListView的其他item会出现向上或者向下滚动的效果,感觉效果很棒,所以在GitHub上面搜索了下,发现很多开源库都有这个效果,比如ListViewAnimations, android-swipelistview等等,我看了下实现原理,使用的是Jake Wharton的动画开源库NineOldAndroids,这个库究竟是干嘛的呢?在API3.0(Honeycomb), SDK新增了一个android.animation包,里面的类是实现动画效果相关的类,通过Honeycomb API,能够实现非常复杂的动画效果,但是如果开发者想在3.0以下使用这一套API, 则需要使用开源框架Nine Old Androids,在这个库中会根据我们运行的机器判断其SDK版本,如果是API3.0以上则使用Android自带的动画类,否则就使用Nine Old Androids库中,这是一个兼容库,接下来我们就来看看这个效果的具体实现吧 实现该效果的主要思路 先根据手指触摸的点来获取点击的是ListView的哪一个Item 当手指在屏幕上面滑动的时候,我们要使得Item跟随手指的滑动而滑动 当我们抬起手指的时候,我们根据滑动的距离或者手指在屏幕上面的速度来判断Item是滑出屏幕还是滑动至其实位置 Item滑出屏幕时,使ListView的其他item产生向上挤压或者向下挤压的效果 大致的思路这是这四步,其中的一些细节接下来我会一一为大家解答的,接下来我们就用代码来实现这种效果吧 首先我们新建一个工程,叫Swipedismisslistview,我们需要将Nine Old Androids这个库引入到工程,大家可以去https://github.com/JakeWharton/NineOldAndroids下载,可以使用Jar包,也可以使用工程库的形式引入到我们自己的工程,我们还需要自定义一个ListView,我们先看代码然后给大家讲解下具体的功能实现 **[java]** [view plain](http://blog.csdn.net/xiaanming/article/details/18311877#)[copy](http://blog.csdn.net/xiaanming/article/details/18311877#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/159353)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/159353/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.swipedismisslistview; - - <span class="keyword">import</span> <span class="keyword">static</span> com.nineoldandroids.view.ViewHelper.setAlpha; - <span class="keyword">import</span> <span class="keyword">static</span> com.nineoldandroids.view.ViewHelper.setTranslationX; - <span class="keyword">import</span> android.content.Context; - <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.view.ViewConfiguration; - <span class="keyword">import</span> android.view.ViewGroup; - <span class="keyword">import</span> android.widget.AdapterView; - <span class="keyword">import</span> android.widget.ListView; - - <span class="keyword">import</span> com.nineoldandroids.animation.Animator; - <span class="keyword">import</span> com.nineoldandroids.animation.AnimatorListenerAdapter; - <span class="keyword">import</span> com.nineoldandroids.animation.ValueAnimator; - <span class="keyword">import</span> com.nineoldandroids.view.ViewHelper; - <span class="keyword">import</span> com.nineoldandroids.view.ViewPropertyAnimator; - <span class="comment">/**</span> - <span class="comment"> * @blog http://blog.csdn.net/xiaanming</span> - <span class="comment"> * </span> - <span class="comment"> * @author xiaanming</span> - <span class="comment"> *</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">class</span> SwipeDismissListView <span class="keyword">extends</span> ListView { - <span class="comment">/**</span> - <span class="comment"> * 认为是用户滑动的最小距离</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mSlop; - <span class="comment">/**</span> - <span class="comment"> * 滑动的最小速度</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mMinFlingVelocity; - <span class="comment">/**</span> - <span class="comment"> * 滑动的最大速度</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mMaxFlingVelocity; - <span class="comment">/**</span> - <span class="comment"> * 执行动画的时间</span> - <span class="comment"> */</span> - <span class="keyword">protected</span> <span class="keyword">long</span> mAnimationTime = <span class="number">150</span>; - <span class="comment">/**</span> - <span class="comment"> * 用来标记用户是否正在滑动中</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">boolean</span> mSwiping; - <span class="comment">/**</span> - <span class="comment"> * 滑动速度检测类</span> - <span class="comment"> */</span> - <span class="keyword">private</span> VelocityTracker mVelocityTracker; - <span class="comment">/**</span> - <span class="comment"> * 手指按下的position</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mDownPosition; - <span class="comment">/**</span> - <span class="comment"> * 按下的item对应的View</span> - <span class="comment"> */</span> - <span class="keyword">private</span> View mDownView; - <span class="keyword">private</span> <span class="keyword">float</span> mDownX; - <span class="keyword">private</span> <span class="keyword">float</span> mDownY; - <span class="comment">/**</span> - <span class="comment"> * item的宽度</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">int</span> mViewWidth; - <span class="comment">/**</span> - <span class="comment"> * 当ListView的Item滑出界面回调的接口</span> - <span class="comment"> */</span> - <span class="keyword">private</span> OnDismissCallback onDismissCallback; - - <span class="comment">/**</span> - <span class="comment"> * 设置动画时间</span> - <span class="comment"> * </span> - <span class="comment"> * @param mAnimationTime</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">void</span> setmAnimationTime(<span class="keyword">long</span> mAnimationTime) { - <span class="keyword">this</span>.mAnimationTime = mAnimationTime; - } - - <span class="comment">/**</span> - <span class="comment"> * 设置删除回调接口</span> - <span class="comment"> * </span> - <span class="comment"> * @param onDismissCallback</span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">void</span> setOnDismissCallback(OnDismissCallback onDismissCallback) { - <span class="keyword">this</span>.onDismissCallback = onDismissCallback; - } - - <span class="keyword">public</span> SwipeDismissListView(Context context) { - <span class="keyword">this</span>(context, <span class="keyword">null</span>); - } - - <span class="keyword">public</span> SwipeDismissListView(Context context, AttributeSet attrs) { - <span class="keyword">this</span>(context, attrs, <span class="number"></span>); - } - - <span class="keyword">public</span> SwipeDismissListView(Context context, AttributeSet attrs, - <span class="keyword">int</span> defStyle) { - <span class="keyword">super</span>(context, attrs, defStyle); - - ViewConfiguration vc = ViewConfiguration.get(context); - mSlop = vc.getScaledTouchSlop(); - mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * <span class="number">8</span>; <span class="comment">//获取滑动的最小速度</span> - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); <span class="comment">//获取滑动的最大速度</span> - } - - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">boolean</span> onTouchEvent(MotionEvent ev) { - <span class="keyword">switch</span> (ev.getAction()) { - <span class="keyword">case</span> MotionEvent.ACTION_DOWN: - handleActionDown(ev); - <span class="keyword">break</span>; - <span class="keyword">case</span> MotionEvent.ACTION_MOVE: - <span class="keyword">return</span> handleActionMove(ev); - <span class="keyword">case</span> MotionEvent.ACTION_UP: - handleActionUp(ev); - <span class="keyword">break</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="comment"> * @param ev</span> - <span class="comment"> * @return</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">void</span> handleActionDown(MotionEvent ev) { - mDownX = ev.getX(); - mDownY = ev.getY(); - - mDownPosition = pointToPosition((<span class="keyword">int</span>) mDownX, (<span class="keyword">int</span>) mDownY); - - <span class="keyword">if</span> (mDownPosition == AdapterView.INVALID_POSITION) { - <span class="keyword">return</span>; - } - - mDownView = getChildAt(mDownPosition &#8211; getFirstVisiblePosition()); - - <span class="keyword">if</span> (mDownView != <span class="keyword">null</span>) { - mViewWidth = mDownView.getWidth(); - } - - <span class="comment">//加入速度检测</span> - mVelocityTracker = VelocityTracker.obtain(); - mVelocityTracker.addMovement(ev); - } - - - <span class="comment">/**</span> - <span class="comment"> * 处理手指滑动的方法</span> - <span class="comment"> * </span> - <span class="comment"> * @param ev</span> - <span class="comment"> * @return</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">boolean</span> handleActionMove(MotionEvent ev) { - <span class="keyword">if</span> (mVelocityTracker == <span class="keyword">null</span> || mDownView == <span class="keyword">null</span>) { - <span class="keyword">return</span> <span class="keyword">super</span>.onTouchEvent(ev); - } - - <span class="comment">// 获取X方向滑动的距离</span> - <span class="keyword">float</span> deltaX = ev.getX() &#8211; mDownX; - <span class="keyword">float</span> deltaY = ev.getY() &#8211; mDownY; - - <span class="comment">// X方向滑动的距离大于mSlop并且Y方向滑动的距离小于mSlop,表示可以滑动</span> - <span class="keyword">if</span> (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < mSlop) { - mSwiping = <span class="keyword">true</span>; - - <span class="comment">//当手指滑动item,取消item的点击事件,不然我们滑动Item也伴随着item点击事件的发生</span> - MotionEvent cancelEvent = MotionEvent.obtain(ev); - cancelEvent.setAction(MotionEvent.ACTION_CANCEL | - (ev.getActionIndex()<< MotionEvent.ACTION_POINTER_INDEX_SHIFT)); - onTouchEvent(cancelEvent); - } - - <span class="keyword">if</span> (mSwiping) { - <span class="comment">// 跟谁手指移动item</span> - ViewHelper.setTranslationX(mDownView, deltaX); - <span class="comment">// 透明度渐变</span> - ViewHelper.setAlpha(mDownView, Math.max(0f, Math.min(1f, 1f &#8211; 2f * Math.abs(deltaX)/ mViewWidth))); - - <span class="comment">// 手指滑动的时候,返回true,表示SwipeDismissListView自己处理onTouchEvent,其他的就交给父类来处理</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"> * @param ev</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">void</span> handleActionUp(MotionEvent ev) { - <span class="keyword">if</span> (mVelocityTracker == <span class="keyword">null</span> || mDownView == <span class="keyword">null</span>|| !mSwiping) { - <span class="keyword">return</span>; - } - - <span class="keyword">float</span> deltaX = ev.getX() &#8211; mDownX; - - <span class="comment">//通过滑动的距离计算出X,Y方向的速度</span> - mVelocityTracker.computeCurrentVelocity(<span class="number">1000</span>); - <span class="keyword">float</span> velocityX = Math.abs(mVelocityTracker.getXVelocity()); - <span class="keyword">float</span> velocityY = Math.abs(mVelocityTracker.getYVelocity()); - - <span class="keyword">boolean</span> dismiss = <span class="keyword">false</span>; <span class="comment">//item是否要滑出屏幕</span> - <span class="keyword">boolean</span> dismissRight = <span class="keyword">false</span>;<span class="comment">//是否往右边删除</span> - - <span class="comment">//当拖动item的距离大于item的一半,item滑出屏幕</span> - <span class="keyword">if</span> (Math.abs(deltaX) > mViewWidth / <span class="number">2</span>) { - dismiss = <span class="keyword">true</span>; - dismissRight = deltaX > <span class="number"></span>; - - <span class="comment">//手指在屏幕滑动的速度在某个范围内,也使得item滑出屏幕</span> - } <span class="keyword">else</span> <span class="keyword">if</span> (mMinFlingVelocity <= velocityX - && velocityX <= mMaxFlingVelocity && velocityY < velocityX) { - dismiss = <span class="keyword">true</span>; - dismissRight = mVelocityTracker.getXVelocity() > <span class="number"></span>; - } - - <span class="keyword">if</span> (dismiss) { - ViewPropertyAnimator.animate(mDownView) - .translationX(dismissRight ? mViewWidth : -mViewWidth)<span class="comment">//X轴方向的移动距离</span> - .alpha(<span class="number"></span>) - .setDuration(mAnimationTime) - .setListener(<span class="keyword">new</span> AnimatorListenerAdapter() { - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onAnimationEnd(Animator animation) { - <span class="comment">//Item滑出界面之后执行删除</span> - performDismiss(mDownView, mDownPosition); - } - }); - } <span class="keyword">else</span> { - <span class="comment">//将item滑动至开始位置</span> - ViewPropertyAnimator.animate(mDownView) - .translationX(<span class="number"></span>) - .alpha(<span class="number">1</span>) - .setDuration(mAnimationTime).setListener(<span class="keyword">null</span>); - } - - <span class="comment">//移除速度检测</span> - <span class="keyword">if</span>(mVelocityTracker != <span class="keyword">null</span>){ - mVelocityTracker.recycle(); - mVelocityTracker = <span class="keyword">null</span>; - } - - mSwiping = <span class="keyword">false</span>; - } - - - - <span class="comment">/**</span> - <span class="comment"> * 在此方法中执行item删除之后,其他的item向上或者向下滚动的动画,并且将position回调到方法onDismiss()中</span> - <span class="comment"> * @param dismissView</span> - <span class="comment"> * @param dismissPosition</span> - <span class="comment"> */</span> - <span class="keyword">private</span> <span class="keyword">void</span> performDismiss(<span class="keyword">final</span> View dismissView, <span class="keyword">final</span> <span class="keyword">int</span> dismissPosition) { - <span class="keyword">final</span> ViewGroup.LayoutParams lp = dismissView.getLayoutParams();<span class="comment">//获取item的布局参数</span> - <span class="keyword">final</span> <span class="keyword">int</span> originalHeight = dismissView.getHeight();<span class="comment">//item的高度</span> - - ValueAnimator animator = ValueAnimator.ofInt(originalHeight, <span class="number"></span>).setDuration(mAnimationTime); - animator.start(); - - animator.addListener(<span class="keyword">new</span> AnimatorListenerAdapter() { - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onAnimationEnd(Animator animation) { - <span class="keyword">if</span> (onDismissCallback != <span class="keyword">null</span>) { - onDismissCallback.onDismiss(dismissPosition); - } - - <span class="comment">//这段代码很重要,因为我们并没有将item从ListView中移除,而是将item的高度设置为0</span> - <span class="comment">//所以我们在动画执行完毕之后将item设置回来</span> - ViewHelper.setAlpha(dismissView, 1f); - ViewHelper.setTranslationX(dismissView, <span class="number"></span>); - ViewGroup.LayoutParams lp = dismissView.getLayoutParams(); - lp.height = originalHeight; - dismissView.setLayoutParams(lp); - - } - }); - - animator.addUpdateListener(<span class="keyword">new</span> ValueAnimator.AnimatorUpdateListener() { - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onAnimationUpdate(ValueAnimator valueAnimator) { - <span class="comment">//这段代码的效果是ListView删除某item之后,其他的item向上滑动的效果</span> - lp.height = (Integer) valueAnimator.getAnimatedValue(); - dismissView.setLayoutParams(lp); - } - }); - - } - - <span class="comment">/**</span> - <span class="comment"> * 删除的回调接口</span> - <span class="comment"> * </span> - <span class="comment"> * @author xiaanming</span> - <span class="comment"> * </span> - <span class="comment"> */</span> - <span class="keyword">public</span> <span class="keyword">interface</span> OnDismissCallback { - <span class="keyword">public</span> <span class="keyword">void</span> onDismiss(<span class="keyword">int</span> dismissPosition); - } - - } 看过Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果你会发现,这个自定义的SwipeDismissListView只重写了onTouchEvent()方法,其实我们重写这一个方法就能实现我们需要的效果 ...

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

android ViewPage动画实现

实现思路 1.使用http://nineoldandroids.com/动画库 https://github.com/JakeWharton/NineOldAndroids https://github.com/jfeinstein10/JazzyViewPager 2.使用3.0以上直接使用 3.自定义Viewpage

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

直接拿来用!最火的Android开源项目

 **21. [drag-sort-listview](https://github.com/bauerca/drag-sort-listview)** DragSortListView(DSLV)是Android ListView的一个扩展,支持拖拽排序和左右滑动删除功能。重写了TouchInterceptor(TI)类来提供更加优美的拖拽动画效果。 [![](http://cms.csdnimg.cn/article/201305/06/5187781b64cbe_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/5187781b64cbe.jpg) [![](http://cms.csdnimg.cn/article/201305/06/5187782519829_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/5187782519829.jpg) DSLV主要特性: - 完美的拖拽支持; - 在拖动时提供更平滑的滚动列表滚动; - 支持每个ListItem高度的多样性 - 公开startDrag()和stopDrag()方法; - 有公开的接口可以自定义拖动的View。 DragSortListView适用于带有任何优先级的列表:收藏夹、播放列表及清单等,算得上是目前Android开源实现拖动排序操作最完美的方案。 **22. [c-geo-opensource](https://github.com/cgeo/c-geo-opensource)** c:geo是Android设备上一个简单而又强大的非官方地理寻宝客户端。与其他类似应用不同的是,c:geo不需要Web浏览器,也不需要文件输出。你可以在毫无准备的情况下,毫无后顾之忧地带上你的智能手机去进行地理寻宝。当然,你也不需要付钱,因为它是免费的。 [![](http://cms.csdnimg.cn/article/201305/07/518894ed23ed2_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518894ed23ed2.jpg) c-geo-opensource包含了c:geo所有开源代码。 详情请参考:[**c:geo**](http://www.cgeo.org/) **23. [NineOldAndroids](https://github.com/JakeWharton/NineOldAndroids)** 自Android 3.0以上的版本,SDK新增了一个android.animation包,里面的类都是跟动画效果实现相关的,通过Honeycomb API,能够实现非常复杂的动画效果。但如果开发者想在3.0以下的版本中也能使用到这套API,那么Nine Old Androids就会是你最好的选择,该API和Honeycomb API完全一样,只是改变了你使用com.nineoldandroids.XXX的入口。 [![](http://cms.csdnimg.cn/article/201305/07/51889435c4f33_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889435c4f33.jpg) 该项目包含两个工程,一个是Library,即为动画效果的实现库,另一个则是Sample,是对如何使用该API的演示。开发者可以直接登陆Google Play下载安装[**Nine Old Androids Sample**](https://play.google.com/store/apps/details?id=com.jakewharton.nineoldandroids.sample),查看演示。 详情请参考:[**Nine Old Androids**](http://nineoldandroids.com/) **24. [ppsspp](https://github.com/hrydgard/ppsspp)** PPSSPP是由GC/Wii模拟器[**Dolphin**](http://dolphin-emu.org/)联合创始人之一Henrik Rydgård开发的一款免费的跨平台开源模拟器,支持Windows、Linux、Mac、Android、iOS、BlackBerry 10等主流计算机与移动操作系统,可直接工作在x86、x64、ARM等CPU平台上,以GNU GPLv2许可协议发布,主要使用C++编写以提高效率和可移植性。 [![](http://cms.csdnimg.cn/article/201305/06/518779953e825_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/518779953e825.jpg) 只要支持OpenGL ES 2.0,PPSSPP就可以在相当低规格的硬件设备上运行,包括基于ARM的手机及平板电脑。 详情请参考:[**PPSSPP**](http://www.ppsspp.org/) **25. [androidquery](https://github.com/androidquery/androidquery)** Android-Query(AQuery)是一个轻量级的开发包,用于实现Android上的异步任务和操作UI元素,可让Android应用开发更简单、更容易,也更有趣。 **26. [droid-fu](https://github.com/mttkay/droid-fu)** Droid-Fu是一个开源的通用Android应用库,其主要目的是为了让Android开发更容易,包含有许多工具类,还有非常易用的Android组件。 Droid-Fu提供支持的领域包括: - Android应用的生命周期帮助 - 支持处理Intents和diagnostics类 - 后台任务支持 - HTTP消息处理 - 对象、HTTP响应及远程图像高速缓存 - 定制各种Adapter及View [![](http://cms.csdnimg.cn/article/201305/07/518897f7199f4_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518897f7199f4.jpg) Droid-Fu最大的优势在于它的应用生命周期帮助类,如果你正在开发一款Android应用,而它的主要任务是运行后台任务,比如从Web上抓取数据,那么,你一定会使用到Droid-Fu,不过,目前该项目在GitHub上已经停止更新维护。 详情请参考:[**droid-fu**](https://github.com/mttkay/droid-fu/wiki) **27. [TextSecure](https://github.com/WhisperSystems/TextSecure)** TextSecure是Whisper Systems团队开发的一个Android上的加密信息客户端,旨在增强用户和企业通信的安全性,其源代码于2011年被Twitter发布在GitHub开源数据库中。 [![](http://cms.csdnimg.cn/article/201305/07/51889740c3bd3_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889740c3bd3.jpg) 该软件允许用户将在Android设备上所有发送和接收的短信内容进行加密,还可以将加密信息发送给另一个TextSecure用户。 **28. [XobotOS](https://github.com/xamarin/XobotOS)** XobotOS是Xamarin的一个研究项目,用于将Android 4.0从Java/Dalvik移植到C#,并对移植后的性能及内存占用情况进行检测。 [![](http://cms.csdnimg.cn/article/201305/06/518779fcb89b9_middle.jpg)](http://cms.csdnimg.cn/article/201305/06/518779fcb89b9.jpg) **29. [ignition](https://github.com/mttkay/ignition)** 在编写Android应用时,通过提供即用组件和包含许多样板文件的实用类,ignition可以让你的Android应用快速起步。ignition涵盖的区域包括: - Widget、Adapter、Dialog等UI组件; - 允许编写简单却强大的网络代码的HTTP Wrapper库; - 加载远程Web图像并进行缓存的类; - 简单但有效的缓存框架(将对所有对象树做出响应的HTTP缓存到内存或硬盘中); - Intents、diagnostics等几个能让API级别更容易向后兼容的帮助类; - 更友好、更强大的AsyncTask实现。 [![](http://cms.csdnimg.cn/article/201305/07/51889448dd732_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889448dd732.jpg) ignition包括三个子项目: - ignition-core——是一个可以直接编译到App中的Android库项目。 - ignition-support——一个标准的Java库项目,被部署为一个普通的JAR,包含了大部分实用工具类。开发者可以独立使用该工程的核心模块。 - ignition-location——一个可以直接编译到应用程序中的Android AspectJ库项目。能够让定位应用在不需要Activity位置更新处理的情况下获取到最新的位置信息。 详情请参考:[**ignition Sample applications**](https://github.com/mttkay/ignition/wiki/Sample-applications) **30. [android_page_curl](https://github.com/harism/android_page_curl)** android_page_curl是一个在Android上使用OpenGL ES实现类似书本翻页效果的示例程序。(点击链接查看[**视频演示**](http://www.youtube.com/watch?v=iwu7P5PCpsw)) [![](http://cms.csdnimg.cn/article/201305/07/51889b43ec9e9_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51889b43ec9e9.jpg) **31. [asmack](https://github.com/Flowdalic/asmack)** 说到aSmack,自然要先提提Smack。Smack API是一个完整的实现了XMPP协议的开源API库,而aSmack则是Smack在Android上的构建版本,于2013年2月初迁移到GitHub上,该资源库并不包含太多的代码,只是一个构建环境。开发者可以利用该API进行基于XMPP协议的即时消息应用程序开发。 详情请参考:[**asmack**](https://code.google.com/p/asmack/) **32. [AndroidBillingLibrary](https://github.com/robotmedia/AndroidBillingLibrary)** In-app Billing是一项Google Play服务,能够让你在应用内进行数字内容销售,可销售的数字内容范围非常广,包括媒体文件、照片等下载内容,还包括游戏级别、药剂、增值服务和功能等虚拟内容。Android Billing Library可以实现In-app Billing的所有规范,并提供更高级的类来进行使用。 [![](http://cms.csdnimg.cn/article/201305/07/5188ae278fb5a_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ae278fb5a.jpg) Google于2012年底正式发布了v3版Android In-app Billing,但截至目前,GitHub上的Android Billing Library还只能支持到v2版,据悉Google将于2013年初对它进行更新。 详情请参考:[**Google Play In-app Billing**](http://developer.android.com/google/play/billing/index.html) **33. [Crouton](https://github.com/keyboardsurfer/Crouton)** Crouton是Android上的一个可以让开发者对环境中的Toast进行替换的类,以一个应用程序窗口的方式显示,而其显示位置则由开发者自己决定。 [![](http://cms.csdnimg.cn/article/201305/07/5188b6491fd81_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188b6491fd81.jpg) 开发者可以直接登陆Google Play下载安装[**Crouton Demo**](https://play.google.com/store/apps/details?id=de.keyboardsurfer.app.demo.crouton),查看应用演示。 **34. [cwac-endless](https://github.com/commonsguy/cwac-endless)** CommonsWare Android Components(CWAC)是一个开源的Android组件库,用来解决Android开发中各个方面的常见问题,每个 CWAC组件打包成一个独立的jar文件,其中就包含cwac-endless。 [![](http://cms.csdnimg.cn/article/201305/07/5188ca3020955_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ca3020955.jpg) cwac-endless提供一个EndlessAdapter,这是一个自动分页的List,当用户浏览到List最后一行时自动请求新的数据。 详情请参考:[**Commons Ware**](http://commonsware.com/cwac) **35. [DiskLruCache](https://github.com/JakeWharton/DiskLruCache)** 在Android应用开发中,为了提高UI的流畅性、响应速度,提供更高的用户体验,开发者常常会绞尽脑汁地思考如何实现高效加载图片,而DiskLruCache实现正是开发者常用的图片缓存技术之一。Disk LRU Cache,顾名思义,硬件缓存,就是一个在文件系统中使用有限空间进行高速缓存。每个缓存项都有一个字符串键和一个固定大小的值。 [![](http://cms.csdnimg.cn/article/201305/07/5188fc60a7729_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188fc60a7729.jpg) 点击链接[**下载**](http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.jakewharton&a=disklrucache&v=LATEST)该库项目。 **36. [Android-SlideExpandableListView](https://github.com/tjerkw/Android-SlideExpandableListView)** 如果你对Android提供的Android ExpandableListView并不满意,一心想要实现诸如Spotify应用那般的效果,那么SlideExpandableListView绝对是你最好的选择。该库允许你自定义每个列表项目中的ListView,一旦用户点击某个按钮,即可实现该列表项目区域滑动。 [![](http://cms.csdnimg.cn/article/201305/07/5188ff9b1a21b_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5188ff9b1a21b.jpg) **37. [gauges-android](https://github.com/github/gauges-android)** Gaug.es for Android是由[**gaug.es**](http://get.gaug.es/)推出的一款在Android设备上对网站流量数据进行实时统计的应用。gauges-android包含了该应用的源代码,开发者可以直接登陆[**Google Play**](https://play.google.com/store/apps/details?id=com.github.mobile.gauges)下载安装该应用。 [![](http://cms.csdnimg.cn/article/201305/07/5189035ebf373_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5189035ebf373.jpg) **38. [acra](https://github.com/ACRA/acra)** ACRA是一个能够让Android应用自动将崩溃报告以谷歌文档电子表的形式进行发送的库,旨在当应用发生崩溃或出现错误行为时,开发者可以获取到相关数据。 [![](http://cms.csdnimg.cn/article/201305/07/5189057f9195e_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/5189057f9195e.jpg) **39. [roboguice](https://github.com/roboguice/roboguice)** RoboGuice是Android平台上基于Google Guice开发的一个库,可以大大简化Android应用开发的代码及一些繁琐重复的代码。给Android带来了简单、易用的依赖注入,如果你使用过Spring或Guice的话,你就会知道这种编程方式是多么的便捷。 [![](http://cms.csdnimg.cn/article/201305/07/518906ff6405e_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/518906ff6405e.jpg) **40. [otto](https://github.com/square/otto)** Otto是由Square发布的一个着重于Android支持的基于Guava的强大的事件总线,在对应用程序不同部分进行解耦之后,仍然允许它们进行有效的沟通。 [![](http://cms.csdnimg.cn/article/201305/07/51890a97dcfc6_middle.jpg)](http://cms.csdnimg.cn/article/201305/07/51890a97dcfc6.jpg) 详情请参考:**[Otto](http://square.github.io/otto/)** - [直接拿来用!最火的Android开源项目(完结篇)](http://www.csdn.net/article/1970-01-01/2815370) - [直接拿来用!最火的iOS开源项目(二)](http://www.csdn.net/article/1970-01-01/2815806) - [直接拿来用!最火的iOS开源项目(三)](http://www.csdn.net/article/1970-01-01/2816230) - [直接拿来用!最火的iOS开源项目(一)](http://www.csdn.net/article/1970-01-01/2815530) - [直接拿来用!Facebook移动开源项目大合集](http://www.csdn.net/article/1970-01-01/2819435) </div>

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

Android原理——回弹ScrollView

回弹的ScrollView 网上看到的通常是ElasticScrollView, 有一个Bug:点击子控件滑动时,滑动无效, 所以针对此问题,我对ElasticScrollView做了改进。 原理图 代码 我在注释中做了详细的说明 <span class="hljs-keyword">import</span> android.content.Context; <span class="hljs-keyword">import</span> android.graphics.Rect; <span class="hljs-keyword">import</span> android.util.AttributeSet; <span class="hljs-keyword">import</span> android.view.MotionEvent; <span class="hljs-keyword">import</span> android.view.View; <span class="hljs-keyword">import</span> android.view.animation.Animation; <span class="hljs-keyword">import</span> android.view.animation.DecelerateInterpolator; <span class="hljs-keyword">import</span> android.view.animation.TranslateAnimation; <span class="hljs-keyword">import</span> android.widget.ScrollView; <span class="hljs-javadoc">/** * Created by Tindle Wei. */</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ElasticScrollView</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ScrollView</span> {</span> <span class="hljs-javadoc">/** * 手指抖动误差 */</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> SHAKE_MOVE_VALUE = <span class="hljs-number">8</span>; <span class="hljs-javadoc">/** * Scrollview内部的view */</span> <span class="hljs-keyword">private</span> View innerView; <span class="hljs-javadoc">/** * 记录innerView最初的Y位置 */</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">float</span> startY; <span class="hljs-javadoc">/** * 记录原始innerView的大小位置 */</span> <span class="hljs-keyword">private</span> Rect outRect = <span class="hljs-keyword">new</span> Rect(); <span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> animationFinish = <span class="hljs-keyword">true</span>; <span class="hljs-keyword">public</span> <span class="hljs-title">ElasticScrollView</span>(Context context) { <span class="hljs-keyword">super</span>(context); } <span class="hljs-keyword">public</span> <span class="hljs-title">ElasticScrollView</span>(Context context, AttributeSet attrs) { <span class="hljs-keyword">super</span>(context, attrs); } <span class="hljs-javadoc">/** * 继承自View * 在xml的所有布局加载完之后执行 */</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinishInflate</span>() { <span class="hljs-keyword">if</span> (getChildCount() > <span class="hljs-number">0</span>) { innerView = getChildAt(<span class="hljs-number">0</span>); } } <span class="hljs-javadoc">/** * 继承自ViewGroup * 返回true, 截取触摸事件 * 返回false, 将事件传递给onTouchEvent()和子控件的dispatchTouchEvent() */</span> <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">onInterceptTouchEvent</span>(MotionEvent ev) { <span class="hljs-comment">// 判断 点击子控件 or 按住子控件滑动</span> <span class="hljs-comment">// 如果点击子控件,则返回 false, 子控件响应点击事件</span> <span class="hljs-comment">// 如果按住子控件滑动,则返回 true, 滑动布局</span> <span class="hljs-keyword">switch</span> (ev.getAction()) { <span class="hljs-keyword">case</span> MotionEvent.ACTION_DOWN: { startY = ev.getY(); <span class="hljs-keyword">break</span>; } <span class="hljs-keyword">case</span> MotionEvent.ACTION_MOVE: { <span class="hljs-keyword">float</span> currentY = ev.getY(); <span class="hljs-keyword">float</span> scrollY = currentY - startY; <span class="hljs-comment">// 是否返回 true</span> <span class="hljs-keyword">return</span> Math.abs(scrollY) > SHAKE_MOVE_VALUE; } } <span class="hljs-comment">// 默认返回 false</span> <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onInterceptTouchEvent(ev); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">onTouchEvent</span>(MotionEvent ev) { <span class="hljs-keyword">if</span> (innerView == <span class="hljs-keyword">null</span>) { <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onTouchEvent(ev); } <span class="hljs-keyword">else</span> { myTouchEvent(ev); } <span class="hljs-keyword">return</span> <span class="hljs-keyword">super</span>.onTouchEvent(ev); } <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">myTouchEvent</span>(MotionEvent ev) { <span class="hljs-keyword">if</span> (animationFinish) { <span class="hljs-keyword">switch</span> (ev.getAction()) { <span class="hljs-keyword">case</span> MotionEvent.ACTION_DOWN: startY = ev.getY(); <span class="hljs-keyword">super</span>.onTouchEvent(ev); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> MotionEvent.ACTION_UP: startY = <span class="hljs-number">0</span>; <span class="hljs-keyword">if</span> (isNeedAnimation()) { animation(); } <span class="hljs-keyword">super</span>.onTouchEvent(ev); <span class="hljs-keyword">break</span>; <span class="hljs-keyword">case</span> MotionEvent.ACTION_MOVE: <span class="hljs-keyword">final</span> <span class="hljs-keyword">float</span> preY = startY == <span class="hljs-number">0</span> ? ev.getY() : startY; <span class="hljs-keyword">float</span> nowY = ev.getY(); <span class="hljs-keyword">int</span> deltaY = (<span class="hljs-keyword">int</span>) (preY - nowY); startY = nowY; <span class="hljs-comment">// 当滚动到最上或者最下时就不会再滚动,这时移动布局</span> <span class="hljs-keyword">if</span> (isNeedMove()) { <span class="hljs-keyword">if</span> (outRect.isEmpty()) { <span class="hljs-comment">// 保存正常的布局位置</span> outRect.set(innerView .getLeft(), innerView.getTop(), innerView.getRight(), innerView.getBottom()); } <span class="hljs-comment">// 移动布局</span> <span class="hljs-comment">// 这里 deltaY/2 为了操作体验更好</span> innerView.layout(innerView.getLeft(), innerView.getTop() - deltaY / <span class="hljs-number">2</span>, innerView.getRight(), innerView.getBottom() - deltaY / <span class="hljs-number">2</span>); } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">super</span>.onTouchEvent(ev); } <span class="hljs-keyword">break</span>; <span class="hljs-keyword">default</span>: <span class="hljs-keyword">break</span>; } } } <span class="hljs-javadoc">/** * 开启移动动画 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">animation</span>() { TranslateAnimation ta = <span class="hljs-keyword">new</span> TranslateAnimation(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, outRect.top - innerView.getTop()); ta.setDuration(<span class="hljs-number">400</span>); <span class="hljs-comment">// 减速变化 为了用户体验更好</span> ta.setInterpolator(<span class="hljs-keyword">new</span> DecelerateInterpolator()); ta.setAnimationListener(<span class="hljs-keyword">new</span> Animation.AnimationListener() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onAnimationStart</span>(Animation animation) { animationFinish = <span class="hljs-keyword">false</span>; } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onAnimationRepeat</span>(Animation animation) { } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onAnimationEnd</span>(Animation animation) { innerView.clearAnimation(); <span class="hljs-comment">// 设置innerView回到正常的布局位置</span> innerView.layout(outRect.left, outRect.top, outRect.right, outRect.bottom); outRect.setEmpty(); animationFinish = <span class="hljs-keyword">true</span>; } }); innerView.startAnimation(ta); } <span class="hljs-javadoc">/** * 是否需要开启动画 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isNeedAnimation</span>() { <span class="hljs-keyword">return</span> !outRect.isEmpty(); } <span class="hljs-javadoc">/** * 是否需要移动布局 */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isNeedMove</span>() { <span class="hljs-keyword">int</span> offset = innerView.getMeasuredHeight() - getHeight(); offset = (offset < <span class="hljs-number">0</span>) ? <span class="hljs-number">0</span>: offset; <span class="hljs-keyword">int</span> scrollY = getScrollY(); <span class="hljs-keyword">return</span> (offset == <span class="hljs-number">0</span> || scrollY == offset); } } 其他说明 下面是继承关系: ElasticScrollView extends ScrollView ScrollView extends FrameLayout FrameLayout extends ViewGroup ViewGroup extends View 解决子控件 截取滑动监听的代码在onInterceptTouchEvent() , 通过监听Y的变化,来判断是点击子控件还是上拉下拉 getMeasuredHeight()返回的是原始测量高度,与屏幕无关, getHeight()返回的是在屏幕上显示的高度。 实际上在当屏幕可以包裹内容的时候,他们的值是相等的,只有当view超出屏幕后,才能看出他们的区别。当超出屏幕后,getMeasuredHeight()等于getHeight()加上屏幕之外没有显示的高度。 getScrollY() 返回的是滑动View显示部分的顶部 转自:http://www.hotpost.co/8699.html ...

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

android源码大放送(实战开发必备)

文件夹 PATH 列表 卷序列号为 000A-8F50 E:. │ javaapk.com文件列表生成工具.bat │ 使用说明.txt │ 免费下载更多源码.url │ 目录列表.txt │ ├─android web应用 │ jqmDemo_static.zip │ jqmMobileDemo-master.zip │ jqmMobileDemo1_1-master.zip │ Location1014.rar │ ├─anko │ anko服务端和客户端源码.rar │ ├─Bmob │ Bmob云后端数据库开发个失物招领的简单案例.zip │ 结合IM_SDK项目源码.zip │ ├─Button按钮 │ 动态添加RadioGroup的RadioButton.zip │ 带有进度条的button.rar │ 自定义组件实现可滑动的ToggleButton的功能..rar │ ├─Dialog对话框 │ android 自定义对话框.rar │ android-styled-dialogs 可自定义样式的dialog.zip │ Android中实现Iphone样式的AlertDialog.zip │ Android实现Windows风格的Dialog.zip │ HerilyAlertDialog完全自定义的Dialog.zip │ 仿QQ的头像选择弹出的对话框,酷似!.zip │ 基本的对话框.rar │ 自定义列表选择Dialog,适用网络请求数据.rar │ 自定义单选、多选对话框及popwindow窗口实例源码.rar │ 自定义彩色Toast.rar │ ├─dlan │ dlna库源代码包.zip │ ├─EditText输入框 │ 前面部分可以编辑后面部分不可编辑的EditText.zip │ ├─Emoji表情 │ 在项目中使用Emoji表情【源代码】.rar ...

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

github源码分享PinnedSectionListView:分组的listView滑动中固定组标题的实现

在很多应用中,看到这样的listview:listview滑动过程中分组标题固定在上方,当第二个组滑上来时,第一个组才跟着上滑,下一个组固定,直到该组也滑出上边缘。世上无难事只怕有心人,在github上就有人做出来了,而且效果很好(后来发现安卓自带应用中联系人应用就是这样的,估计github的作者也是仿照着联系人做出来的吧)。 先看截图: PinnedSectionListView继承自listview,众所周知listview的每个子view都是按顺序跟着滚动的,要实现联系人listview的效果还真的找不到思路。看了PinnedSectionListView之后,感觉要改造一个现有的控件,一般都是通过重绘子view来实现的。ViewGroup(ListView继承自它)重绘子view的方法是dispatchDraw。 看看PinnedSectionListView在dispatchDraw中有那些特别的处理: 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> <div class="line number15 index14 alt2"> 15 </div> <div class="line number16 index15 alt1"> 16 </div> <div class="line number17 index16 alt2"> 17 </div> <div class="line number18 index17 alt1"> 18 </div> <div class="line number19 index18 alt2"> 19 </div> <div class="line number20 index19 alt1"> 20 </div> <div class="line number21 index20 alt2"> 21 </div> <div class="line number22 index21 alt1"> 22 </div> <div class="line number23 index22 alt2"> 23 </div> <div class="line number24 index23 alt1"> 24 </div> <div class="line number25 index24 alt2"> 25 </div> </td> <td class="code"> <div class="container"> <div class="line number1 index0 alt2"> `@Override` </div> <div class="line number2 index1 alt1"> `protected void dispatchDraw(Canvas canvas) {` </div> <div class="line number3 index2 alt2"> ` ``super``.dispatchDraw(canvas);` </div> <div class="line number4 index3 alt1"> ` ``if` `(mPinnedSection != ``null``) {` </div> <div class="line number5 index4 alt2"> ` ``// prepare variables` </div> <div class="line number6 index5 alt1"> ` ``int pLeft = getListPaddingLeft();` </div> <div class="line number7 index6 alt2"> ` ``int pTop = getListPaddingTop();` </div> <div class="line number8 index7 alt1"> ` ``View view = mPinnedSection.view;` </div> <div class="line number9 index8 alt2"> ` ``// draw child` </div> <div class="line number10 index9 alt1"> ` ``canvas.save();` </div> <div class="line number11 index10 alt2"> ` ``int clipHeight = view.getHeight() +` </div> <div class="line number12 index11 alt1"> ` ``(mShadowDrawable == ``null` `? 0 : Math.min(mShadowHeight, mSectionsDistanceY));` </div> <div class="line number13 index12 alt2"> ` ``canvas.clipRect(pLeft, pTop, pLeft + view.getWidth(), pTop + clipHeight);` </div> <div class="line number14 index13 alt1"> ` ``canvas.translate(pLeft, pTop + mTranslateY);` </div> <div class="line number15 index14 alt2"> ` ``drawChild(canvas, mPinnedSection.view, getDrawingTime());` </div> <div class="line number16 index15 alt1"> ` ``if` `(mShadowDrawable != ``null` `&& mSectionsDistanceY &gt; 0) {` </div> <div class="line number17 index16 alt2"> ` ``mShadowDrawable.setBounds(mPinnedSection.view.getLeft(),` </div> <div class="line number18 index17 alt1"> ` ``mPinnedSection.view.getBottom(),` </div> <div class="line number19 index18 alt2"> ` ``mPinnedSection.view.getRight(),` </div> <div class="line number20 index19 alt1"> ` ``mPinnedSection.view.getBottom() + mShadowHeight);` </div> <div class="line number21 index20 alt2"> ` ``mShadowDrawable.draw(canvas);` </div> <div class="line number22 index21 alt1"> ` ``}` </div> <div class="line number23 index22 alt2"> ` ``canvas.restore();` </div> <div class="line number24 index23 alt1"> ` ``}` </div> <div class="line number25 index24 alt2"> `}` </div> </div> </td> </tr> </table> 关键在于```canvas.translate(pLeft, pTop + mTranslateY);意思是在绘制mPinnedSection的时候,listview滑动了多长的距离,就将canvas移动多少的距离,使mPinnedSection`始终在可见的范围内固定不变。 ...

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

Android 对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果

转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming),请尊重他人的辛勤劳动成果,谢谢! 随着移动互联网的快速发展,它已经和我们的生活息息相关了,在公交地铁里面都能看到很多人的人低头看着自己的手机屏幕,从此“低头族”一词就产生了,作为一名移动行业的开发人员,我自己也是一名“低头族”,上下班时间在公交地铁上看看新闻来打发下时间,有时候也会看看那些受欢迎的App的一些界面效果,为什么人家的app那么受欢迎?跟用户体验跟UI设计也有直接的关系,最近在美团和大众点评的App看到如下效果,我感觉用户好,很人性化,所以自己也尝试着实现了下,接下来就讲解下实现思路! 如上图(2)我们看到了,当立即抢购布局向上滑动到导航栏布局的时候,立即抢购布局就贴在导航栏布局下面,下面的其他的布局还是可以滑动,当我们向下滑动的时候,立即抢购的布局又随着往下滑动了,看似有点复杂,但是一说思路可能你就顿时恍然大悟了。 当我们向上滑动过程中,我们判断立即抢购的布局是否滑到导航栏布局下面,如果立即抢购的上面顶到了导航栏,我们新建一个立即抢购的悬浮框来显示在导航栏下面,这样子就实现了立即抢购贴在导航栏下面的效果啦,而当我们向下滑动的时候,当立即抢购布局的下面刚好到了刚刚新建的立即抢购悬浮框的下面的时候,我们就移除立即抢购悬浮框,可能说的有点拗口,既然知道了思路,接下来我们就来实现效果。 新建一个Android项目,取名MeiTuanDemo,先看立即抢购(buy_layout.xml)的布局,这里为了方便我直接从美团上面截去了图片 **[html]** [view plain](http://blog.csdn.net/xiaanming/article/details/17374599#)[copy](http://blog.csdn.net/xiaanming/article/details/17374599#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/120124)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/120124/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="tag"><?</span><span class="tag-name">xml</span> <span class="attribute">version</span>=<span class="attribute-value">&#8220;1.0&#8221;</span> <span class="attribute">encoding</span>=<span class="attribute-value">&#8220;UTF-8&#8221;</span><span class="tag">?></span> - <span class="tag"><</span><span class="tag-name">LinearLayout</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span> - <span class="attribute">android:orientation</span>=<span class="attribute-value">&#8220;horizontal&#8221;</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;wrap_content&#8221;</span> <span class="tag">></span> - - <span class="tag"><</span><span class="tag-name">ImageView</span> - <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/buy_layout&#8221;</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;wrap_content&#8221;</span> - <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;@drawable/buy&#8221;</span> <span class="tag">/></span> - - <span class="tag"></</span><span class="tag-name">LinearLayout</span><span class="tag">></span> 立即抢购的布局实现了,接下来实现主界面的布局,上面是导航栏布局,为了方便还是直接从美团截取的图片,然后下面的ViewPager布局,立即抢购布局,其他布局 放在ScrollView里面,界面还是很简单的 ...

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