上一次我们试验了有弹性的ScrollView。详情

这一次,我们来试验有弹性的ScrollView。

国际惯例,效果图:

主要代码:

[java] view
plain
copy

  1. import android.content.Context;
  2. import android.graphics.Rect;
  3. import android.util.AttributeSet;
  4. import android.view.MotionEvent;
  5. import android.view.animation.Animation;
  6. import android.view.animation.Animation.AnimationListener;
  7. import android.view.animation.TranslateAnimation;
  8. import android.widget.AbsListView;
  9. import android.widget.ListView;
  10. /**
  11. * ElasticScrollView有弹性的ListView
  12. */
  13. public class ElasticListView extends ListView {
  14. private float y;
  15. private Rect normal = new Rect();
  16. private boolean animationFinish = true;
  17. public ElasticListView(Context context) {
  18. super(context);
  19. init();
  20. }
  21. public ElasticListView(Context context, AttributeSet attrs) {
  22. super(context, attrs);
  23. init();
  24. }
  25. protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  26. }
  27. boolean overScrolled = false;
  28. private void init() {
  29. setOnScrollListener(new OnScrollListener() {
  30. @Override
  31. public void onScrollStateChanged(AbsListView view, int scrollState) {
  32. }
  33. @Override
  34. public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  35. overScrolled = false;
  36. }
  37. });
  38. }
  39. @Override
  40. protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
  41. overScrolled = true;
  42. }
  43. @Override
  44. public boolean onTouchEvent(MotionEvent ev) {
  45. commOnTouchEvent(ev);
  46. return super.onTouchEvent(ev);
  47. }
  48. public void commOnTouchEvent(MotionEvent ev) {
  49. if (animationFinish) {
  50. int action = ev.getAction();
  51. switch (action) {
  52. case MotionEvent.ACTION_DOWN:
  53. y = ev.getY();
  54. break;
  55. case MotionEvent.ACTION_UP:
  56. y = 0;
  57. if (isNeedAnimation()) {
  58. animation();
  59. }
  60. break;
  61. case MotionEvent.ACTION_MOVE:
  62. final float preY = y == 0 ? ev.getY() : y;
  63. float nowY = ev.getY();
  64. int deltaY = (int) (preY - nowY);
  65. y = nowY;
  66. // 当滚动到最上或者最下时就不会再滚动,这时移动布局
  67. if (isNeedMove(deltaY)) {
  68. if (normal.isEmpty()) {
  69. // 保存正常的布局位置
  70. normal.set(getLeft(), getTop(), getRight(), getBottom());
  71. }
  72. // 移动布局
  73. layout(getLeft(), getTop() - deltaY / 2, getRight(), getBottom() - deltaY / 2);
  74. }
  75. break;
  76. default:
  77. break;
  78. }
  79. }
  80. }
  81. // 开启动画移动
  82. public void animation() {
  83. // 开启移动动画
  84. TranslateAnimation ta = new TranslateAnimation(0, 0, 0, normal.top - getTop());
  85. ta.setDuration(200);
  86. ta.setAnimationListener(new AnimationListener() {
  87. @Override
  88. public void onAnimationStart(Animation animation) {
  89. animationFinish = false;
  90. }
  91. @Override
  92. public void onAnimationRepeat(Animation animation) {
  93. }
  94. @Override
  95. public void onAnimationEnd(Animation animation) {
  96. clearAnimation();
  97. // 设置回到正常的布局位置
  98. layout(normal.left, normal.top, normal.right, normal.bottom);
  99. normal.setEmpty();
  100. animationFinish = true;
  101. }
  102. });
  103. startAnimation(ta);
  104. }
  105. // 是否需要开启动画
  106. public boolean isNeedAnimation() {
  107. return !normal.isEmpty();
  108. }
  109. // 是否需要移动布局
  110. public boolean isNeedMove(float deltaY) {
  111. if (overScrolled && getChildCount() > 0) {
  112. if (getLastVisiblePosition() == getCount() - 1 && deltaY > 0) {
  113. return true;
  114. }
  115. if (getFirstVisiblePosition() == 0 && deltaY < 0) {
  116. return true;
  117. }
  118. }
  119. return false;
  120. }
  121. }

测试代码:

[java] view
plain
copy

  1. public class MainActivity extends Activity {
  2. ElasticListView listView;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. listView = (ElasticListView) findViewById(R.id.listview);
  8. String[] listValues = new String[20];
  9. for (int i=0;i<listValues.length;i++) {
  10. listValues[i] = "TextView" + i;
  11. }
  12. listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listValues));
  13. }
  14. }
[html] view
plain
copy

  1. public class MainActivity extends Activity {
  2. ElasticListView listView;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. listView = (ElasticListView) findViewById(R.id.listview);
  8. String[] listValues = new String[20];
  9. for (int i=0;i<listValues.length;i++) {
  10. listValues[i] = "TextView" + i;
  11. }
  12. listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listValues));
  13. }
  14. }
public class FlexibleScrollView extends ScrollView {  

    private Context mContext;
private static int mMaxOverDistance = 50; public FlexibleScrollView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initView();
} public FlexibleScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initView();
} public FlexibleScrollView(Context context) {
super(context);
this.mContext = context;
initView();
} private void initView() {
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
float density = metrics.density;
mMaxOverDistance = (int) (density * mMaxOverDistance);
} @Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, maxOverScrollX, mMaxOverDistance,
isTouchEvent);
}
}

通过上面这个类也可以实现弹性效果

二、仿朋友圈背景图片下拉

public class ScrollDampView extends ScrollView {
/** 该属性具体参数 怎么控制 未解!!!! */
private static final int LEN = 0xc8;
/** 回弹时所用的时间 */
private static final int DURATION = 200;
/** 最大Y坐标 其值一般设定为Scroller对应控件的高度 */
private static final int MAX_DY = 200; private Scroller mScroller;
/** 阻尼系数 */
private static final float OFFSET_RADIO = 2.5f; private float startY;
private int imageViewH; private ImageView imageView;
private boolean scrollerType; public ScrollDampView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); } public ScrollDampView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
} public ScrollDampView(Context context) {
super(context); } public void setImageView(ImageView imageView) {
this.imageView = imageView;
} float curY; @Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
if (!mScroller.isFinished()) {
return super.onTouchEvent(event);
}
switch (action) {
case MotionEvent.ACTION_DOWN:// 变量赋初始值
imageViewH = imageView.getHeight();
startY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
if (imageView.isShown()) {
float deltaY = (event.getY() - startY ) / OFFSET_RADIO;
Log.i("syso", "deltaY: "+deltaY+" imageTop: "+imageView.getTop());
//往下拉
if (deltaY > 0 && deltaY <= imageView.getBottom() + LEN) {
android.view.ViewGroup.LayoutParams params = imageView.getLayoutParams();
params.height = (int) (imageViewH + deltaY);// 改变高度
imageView.setLayoutParams(params);
}
scrollerType = false;
}
break;
case MotionEvent.ACTION_UP:
scrollerType = true;
// 开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位
// ,即到达坐标为(startX+dx , startY+dy)处
mScroller.startScroll(imageView.getLeft(), imageView.getBottom(),
0 - imageView.getLeft(),
imageViewH - imageView.getBottom(), DURATION);
invalidate();
break;
} return super.dispatchTouchEvent(event);
} // //该mScroller针对于imageView的变化
// 被父视图调用,用于必要时候对其子视图的值(mScrollX和mScrollY)
// 进行更新。典型的情况如:父视图中某个子视图使用一个Scroller对象来实现滚动操作,会使得此方法被调用。
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();// ImageView的当前Y坐标
imageView.layout(0, 0, x + imageView.getWidth(), y);// 使imageView本身做相应变化
invalidate();
// 滑动还未完成时,手指抬起时,当前y坐标大于其实imageView的高度时
// 设定imageView的布局参数 作用:使除imageView之外的控件做相应变化
if (!mScroller.isFinished() && scrollerType && y > MAX_DY) {
android.view.ViewGroup.LayoutParams params = imageView
.getLayoutParams();
params.height = y;
imageView.setLayoutParams(params);
}
}
} }

布局文件:

<com.example.dampview.ScrollDampView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dampview"
android:layout_width="match_parent"
android:layout_height="match_parent" > <LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <!--此处必须设置imageview的scaleType为centerCrop,当然在代码中设置也可以-->
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="160dp"
android:scaleType="centerCrop"
android:src="@drawable/image" /> <ImageView
android:id="@+id/iv_photo"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginTop="-32dp"
android:src="@drawable/ic_launcher"
/> </LinearLayout> </com.example.dampview.ScrollDampView>

Android自定义控件——有弹性的ListView,ScrollView的更多相关文章

  1. android 自定义控件之NetWorkImageView 处理listview等控件中的图片加载乱序问题

    0.调用: BaseAdapter中设置方法 holder.iv.loadImage(url); adapter_xxx.xml 中 控件需要用 xxx.NetWorkImageView 1 NetW ...

  2. Android自定义控件(三)——有弹性的ListView

    上一次我们试验了有弹性的ScrollView.详情 这一次,我们来试验有弹性的ScrollView. 国际惯例,效果图: 主要代码: import android.content.Context; i ...

  3. 【转】Android自定义控件(三)——有弹性的ListView

    原文地址:http://blog.csdn.net/a105865708/article/details/17959459 上一次我们试验了有弹性的ScrollView.详情 这一次,我们来试验有弹性 ...

  4. Android自定义控件(四)——让每一个Activity UI都具有弹性

    前面我们已经介绍了如何让你的ScrollView,ListView具有弹性, 今天,我们在前面的基础上,做一下适当的修改,让那些既不是ScrollView,也不是ListView的Activity页面 ...

  5. android 关于listview scrollview 底部 控件无法显示的两个解决方案

    方案一 用LinearLayout实现,代码如下: <!-- 中奖纪录 by mhd --> <LinearLayout xmlns:android="http://sch ...

  6. Android自定义控件 开源组件SlidingMenu的项目集成

    在实际项目开发中,定制一个菜单,能让用户得到更好的用户体验,诚然菜单的样式各种各样,但是有一种菜单——滑动菜单,是被众多应用广泛使用的.关于这种滑动菜单的实现,我在前面的博文中也介绍了如何自定义去实现 ...

  7. 【转】Android之自定义Adapter的ListView

    http://www.cnblogs.com/topcoderliu/archive/2011/05/07/2039862.html 在开发中,我们经常使用到ListView这个控件.Android的 ...

  8. android 自定义控件二之仿QQ长按删除

    自定义Dialog 1.先上个效果图:

  9. Android之自定义Adapter的ListView

    ListView的创建,一般要具备两大元素: 1)数据集,即要映射的字符串.图片信息之类. 2)适配器,实现把要映射的字符串.图片信息映射成视图(如Textview.Image等组件),再添加到Lis ...

随机推荐

  1. 手机浏览器的User-Agent汇总

    手机浏览器的User-Agent汇总 之前介绍的 更简洁的方式修改Chrome的User Agent,轻松体验移动版网络这种简洁的方法好像只适用于Chrome, Chrome不只是浏览界面简洁,对应的 ...

  2. canvas中strokeRect的渲染问题>>strokeRect把一像素的边框渲染成两像素

    > 结论写在头 var oC = document.getElementById('c1'); var oGC = oC.getContext('2d'); oGC.strokeRect(50, ...

  3. 引入 Tinker 之后如何在 Debug 模式下开启 Instant Run

    在<Tinker + Bugly + Jenkins 爬坑之路>一文中讲了在接入 Tinker 之后,Jenkins 中的一些坑,由此,热修复算告一段落,但是,在直接 Run 模式运行时, ...

  4. python 静态 封装 继承 mro 接口 super

    1.静态属性 静态方法  类方法 #!/usr/bin/python env # encoding: utf-8 # 静态属性 静态方法 class Room: tag = 168 def __ini ...

  5. springboot中filter的配置和顺序执行

    项目结构 springboot版本 <parent> <groupId>org.springframework.boot</groupId> <artifac ...

  6. springDataJpa学习笔记

    目录 前言 springData 准备 引用 xml配置初始化JPA pojo dao层接口 使用 新增.修改:save 删除 查询所有 根据ID查询findById 命名规则查询(条件查询) 自定义 ...

  7. 从golang-gin-realworld-example-app项目学写httpapi (八)

    https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/common/unit_test.go 单元测试 ...

  8. Oracle常用名词解释

    好久没做rac,最近要做架构梳理,这里针对Oracle常用的名词缩写,这里做个记录,希望对大家有所帮助. RAC 全称是Real Application Cluster,oracle的高可用群集,即实 ...

  9. SVN global ignore pattern

    *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo *.rej *~ #*# .#* .*.swp .DS_Store */bin */ ...

  10. 乘风破浪:LeetCode真题_002_Add Two Numbers

    乘风破浪:LeetCode真题_002_Add Two Numbers 一.前言     这次的题目是关于链表方面的题目,把两个链表对应节点相加,还要保证进位,每个节点都必须是十进制的0~9.因此主要 ...