背景介绍

最近项目打算做一个界面,类似于dayone首页的界面效果,dayone 是一款付费应用,目前只有IOS端。作为一个资深懒惰的程序员,奉行的宗旨是绝对不重复造一个轮子。于是乎,去网上找一大堆开源项目,发现没有找到合适的,然后,只能硬着头皮自己来了。先看看效果:

其实写起来也比较简单,就是控制ListView的头部和底部的高度就可以了, 如果用RecycleView实现起来也是一样,只是RecycleView添加头和尾巴稍微麻烦一点,处理点击事件也不是很方便,所以就基于ListView去实现了。

实现的代码, 我已经上传到github上了。

使用方法

github地址: https://github.com/yll2wcf/YLListView 可以帮我点个star啊~

使用方法

 compile 'com.a520wcf.yllistview:YLListView:1.0.1'

使用介绍:

布局:
布局注意一个小细节android:layout_height 最好是match_parent, 否则ListView每次滑动的时候都有可能需要重新计算条目高度,比较耗费CPU;

    <com.a520wcf.yllistview.YLListViewandroid:divider="@android:color/transparent"android:id="@+id/listView"android:layout_width="match_parent"android:layout_height="match_parent"/>  

代码:

   private YLListView listView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listView = (YLListView) findViewById(R.id.listView);// 不添加也有默认的头和底View topView=View.inflate(this,R.layout.top,null);listView.addHeaderView(topView);View bottomView=new View(getApplicationContext());listView.addFooterView(bottomView);// 顶部和底部也可以固定最终的高度 不固定就使用布局本身的高度listView.setFinalBottomHeight(100);listView.setFinalTopHeight(100);listView.setAdapter(new DemoAdapter());//YLListView默认有头和底  处理点击事件位置注意减去listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {position=position-listView.getHeaderViewsCount();}});}

源码介绍

其实这个项目里面只有一个类,大家不需要依赖,直接把这个类复制到项目中就可以了,来看看源码:

package com.a520wcf.yllistview;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.Scroller;/*** 邮箱 yll@520wcf.com* Created by yull on 12/17.*/
public class YLListView extends ListView implements AbsListView.OnScrollListener {private Scroller mScroller; // used for scroll backprivate float mLastY = -1;private int mScrollBack;private final static int SCROLLBACK_HEADER = 0;private final static int SCROLLBACK_FOOTER = 1;private final static int SCROLL_DURATION = 400; // scroll back durationprivate final static float OFFSET_RADIO = 1.8f;// total list items, used to detect is at the bottom of ListView.private int mTotalItemCount;private View mHeaderView;  // 顶部图片private View mFooterView;  // 底部图片private int finalTopHeight;private int finalBottomHeight;public YLListView(Context context) {super(context);initWithContext(context);}public YLListView(Context context, AttributeSet attrs) {super(context, attrs);initWithContext(context);}public YLListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initWithContext(context);}private void initWithContext(Context context) {mScroller = new Scroller(context, new DecelerateInterpolator());super.setOnScrollListener(this);this.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {if(mHeaderView==null){View view=new View(getContext());addHeaderView(view);}if(mFooterView==null){View view=new View(getContext());addFooterView(view);}getViewTreeObserver().removeGlobalOnLayoutListener(this);}});}@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (mLastY == -1) {mLastY = ev.getRawY();}switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:mLastY = ev.getRawY();break;case MotionEvent.ACTION_MOVE:final float deltaY = ev.getRawY() - mLastY;mLastY = ev.getRawY();if (getFirstVisiblePosition() == 0 && (mHeaderView.getHeight() > finalTopHeight || deltaY > 0)&& mHeaderView.getTop() >= 0) {// the first item is showing, header has shown or pull down.updateHeaderHeight(deltaY / OFFSET_RADIO);} else if (getLastVisiblePosition() == mTotalItemCount - 1&& (getFootHeight() >finalBottomHeight || deltaY < 0)) {updateFooterHeight(-deltaY / OFFSET_RADIO);}break;default:mLastY = -1; // resetif (getFirstVisiblePosition() == 0 && getHeaderHeight() > finalTopHeight) {resetHeaderHeight();}if (getLastVisiblePosition() == mTotalItemCount - 1 ){if(getFootHeight() > finalBottomHeight) {resetFooterHeight();}}break;}return super.onTouchEvent(ev);}/*** 重置底部高度*/private void resetFooterHeight() {int bottomHeight = getFootHeight();if (bottomHeight > finalBottomHeight) {mScrollBack = SCROLLBACK_FOOTER;mScroller.startScroll(0, bottomHeight, 0, -bottomHeight+finalBottomHeight,SCROLL_DURATION);invalidate();}}// 计算滑动  当invalidate()后 系统会自动调用@Overridepublic void computeScroll() {if (mScroller.computeScrollOffset()) {if (mScrollBack == SCROLLBACK_HEADER) {setHeaderHeight(mScroller.getCurrY());} else {setFooterViewHeight(mScroller.getCurrY());}postInvalidate();}super.computeScroll();}// 设置顶部高度private void setHeaderHeight(int height) {LayoutParams layoutParams = (LayoutParams) mHeaderView.getLayoutParams();layoutParams.height = height;mHeaderView.setLayoutParams(layoutParams);}// 设置底部高度private void setFooterViewHeight(int height) {LayoutParams layoutParams =(LayoutParams) mFooterView.getLayoutParams();layoutParams.height =height;mFooterView.setLayoutParams(layoutParams);}// 获取顶部高度public int getHeaderHeight() {AbsListView.LayoutParams layoutParams =(AbsListView.LayoutParams) mHeaderView.getLayoutParams();return layoutParams.height;}// 获取底部高度public int getFootHeight() {AbsListView.LayoutParams layoutParams =(AbsListView.LayoutParams) mFooterView.getLayoutParams();return layoutParams.height;}private void resetHeaderHeight() {int height = getHeaderHeight();if (height == 0) // not visible.return;mScrollBack = SCROLLBACK_HEADER;mScroller.startScroll(0, height, 0, finalTopHeight - height,SCROLL_DURATION);invalidate();}/*** 设置顶部高度  如果不设置高度,默认就是布局本身的高度* @param height 顶部高度*/public void setFinalTopHeight(int height) {this.finalTopHeight = height;}/*** 设置底部高度  如果不设置高度,默认就是布局本身的高度* @param height 底部高度*/public void setFinalBottomHeight(int height){this.finalBottomHeight=height;}@Overridepublic void addHeaderView(View v) {mHeaderView = v;super.addHeaderView(mHeaderView);mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {if(finalTopHeight==0) {finalTopHeight = mHeaderView.getMeasuredHeight();}setHeaderHeight(finalTopHeight);getViewTreeObserver().removeGlobalOnLayoutListener(this);}});}@Overridepublic void addFooterView(View v) {mFooterView = v;super.addFooterView(mFooterView);mFooterView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {if(finalBottomHeight==0) {finalBottomHeight = mFooterView.getMeasuredHeight();}setFooterViewHeight(finalBottomHeight);getViewTreeObserver().removeGlobalOnLayoutListener(this);}});}private OnScrollListener mScrollListener; // user's scroll listener@Overridepublic void setOnScrollListener(OnScrollListener l) {mScrollListener = l;}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {if (mScrollListener != null) {mScrollListener.onScrollStateChanged(view, scrollState);}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// send to user's listenermTotalItemCount = totalItemCount;if (mScrollListener != null) {mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,totalItemCount);}}private void updateHeaderHeight(float delta) {setHeaderHeight((int) (getHeaderHeight()+delta));setSelection(0); // scroll to top each time}private void updateFooterHeight(float delta) {setFooterViewHeight((int) (getFootHeight()+delta));}
}

转载于:https://www.cnblogs.com/hehe520/p/6329905.html

仿IOS效果-带弹簧动画的ListView相关推荐

  1. Android仿IOS吸边弹簧阻尼移动组件SpringMovingView-自定义view系列(3)

    () Android仿ios吸边弹簧阻尼效果的移动组件SpringMovingView 功能简介 Android技术生活交流 Gif演示 实现步骤 java代码 Android技术生活交流 更多其他页 ...

  2. iOS中实现弹簧动画

    我们都知道iOS9 CASpringAnimation 弹簧动画,操作简单,容易实现,目前使用也比较广泛,下面我给大家介绍一种pop的弹簧效果,跟CASpringAnimation 弹簧动画 很相似 ...

  3. android菊花动画,仿ios系统加载动画(菊花旋转)

    无需添加图片,通过自定义view方式绘制菊花图,代码极简 效果图: image 一.自定义loadingview: public class LoadingView extends View { pr ...

  4. android 仿ios带弹簧效果的ScrollView

    说ios的效果确实不错,今天就参照别人的代码,修改bug一箩筐,优化体验一大堆. 废话不多说,上代码: /**  * 仿ios弹簧效果 scrollview 带阻尼  * @author sunxia ...

  5. 安卓设置菊花动画_Android仿ios加载loading菊花图效果

    项目中经常会用到加载数据的loading显示图,除了设计根据app自身设计的动画loading,一般用的比较多的是仿照ios 的菊花加载loading 图,当然一些条件下还会涉及到加载成功/ 失败情况 ...

  6. android 仿ios动画效果代码,Android仿IOS上拉下拉弹性效果的实例代码

    用过iphone的朋友相信都体验过页面上拉下拉有一个弹性的效果,使用起来用户体验很好:Android并没有给我们封装这样一个效果,我们来看下在Android里如何实现这个效果.先看效果,感觉有些时候还 ...

  7. android菊花动画,Android实现仿iOS菊花加载圈动画效果

    常见的实现方式 切图,做旋转动画 自定义View,绘制效果 gif图 1.切图会增加体积,但相对简单,不过在换肤的场景下,会使用不同颜色,需要准备多张图,不够灵活. 2.由于自定义的好处,不同颜色只需 ...

  8. android 高仿ios开关,Android自定义view仿IOS开关效果

    本文主要讲解如何在 Android 下实现高仿 iOS 的开关按钮,并非是在 Android 自带的 ToggleButton 上修改,而是使用 API 提供的 onDraw.onMeasure.Ca ...

  9. Android之高仿QQ6.6.0侧滑效果(背景动画、透明+沉浸式状态栏、渐变效果)

    根据需求实现类似QQ侧滑效果,之前看到过很多实现方式通过SlidingMenu,但是既然官方推出了自己的专属控件,那么使用DrawerLayout就是不二选择.且看下文. 一.先来看看官方文档解释 D ...

最新文章

  1. python 地理信息_GitHub - sujeek/geospatial-data-analysis-cn: Python地理信息数据教程中文版(GeoPandas、GIS)...
  2. Invalid options object. Copy Plugin has been initialized using an options object that does not match
  3. 接口测试(apipost、jmeter和python脚本)
  4. Apache Rewrite实现URL的跳转和域名跳转
  5. java springboot b2b2c shop 多用户商城系统源码(四):熔断器Hystrix
  6. vue3.0 execle 导出功能实现
  7. python 占用内存过高_PyCharm如何优化?太占内存了,太慢了
  8. linux虚拟磁盘服务,hintsoft Linux iscsi虚拟磁盘完全教程及优化攻略
  9. STM32串口屏学习
  10. 8通道250MSPS 14位AD采集FMC子卡
  11. 全面理解document.write()
  12. win7系统安装高版本node
  13. 5G时代下催生了云电脑,云电脑带来了什么?
  14. gitlab日常使用命令
  15. Runtime.exec()执行linux shell
  16. CRM下午茶(七)-潜在客户流失排查
  17. 跟着我从零开始入门FPGA(一周入门系列 第一天)
  18. Elasticsearch:shard 分配感知
  19. 8、Goroutines和Channels
  20. 【VRP问题】基于节约算法CW求解带硬时间窗的车辆路径规划问题(VRPTW)matlab源码

热门文章

  1. 算法优化:rgb向yuv的转化最优算法,快得让你吃惊!
  2. 安装最新版git,git升级
  3. How to Run a Stress Test in JMeter
  4. 新增的querySelector、querySelectorAll测试
  5. 子数组最大值设计02
  6. Mysql 各个版本区别
  7. Jquery ajax jsonp跨域访问 返回格式及其获取方式 并实现单点登录SSO
  8. EZ430 Chronos 如何提高开发调试效率探讨
  9. error LNK2019: 无法解析的外部符号 __imp__inet_ntoa@4
  10. cocos2d-x温故(三)!