Android仿QQ好友详情页下拉顶部图片缩放效果
时间:2022-07-28
本文章向大家介绍Android仿QQ好友详情页下拉顶部图片缩放效果,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
今天已经是这个星期连续加班的第四天了,趁着现在后台在处理逻辑问题,将前几天写的一个小例子整理下来。
效果图
效果分析
1 向下滑动,头部的图片随着手指滑动不断变大 2 向上滑动,不断的向上移动图片,直到图片不可见 3 当顶部图片不可见时,向上滑动,滑动ListView
实现思路
1 由于这个View分上下两部分,垂直排列,可以通过继承LinearLayout实现::自定义一个DragImageView,该View继承LinearLayout
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
// 默认该View垂直排列
setOrientation(LinearLayout.VERTICAL);
// 用于配合处理该View的惯性滑动
mScroller = new OverScroller(context);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mMaximumVelocity = ViewConfiguration.get(context)
.getScaledMaximumFlingVelocity();
mMinimumVelocity = ViewConfiguration.get(context)
.getScaledMinimumFlingVelocity();
}
2 onMeasure中设置内容视图的高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
LayoutParams params = (LayoutParams) getChildAt(1).getLayoutParams();
// 头部可以全部隐藏,所以内容视图的高度即为该控件的高度
params.height = getMeasuredHeight();
}
3 设置ImageView的ScaleType属性
@Override
protected void onFinishInflate() {
super.onFinishInflate();
imageView = (ImageView) getChildAt(0);
// 随着手指滑动,图片不断放大(宽高都大于或者等于ImageView的大小),并居中显示:
// 根据上边的分析,CENTER_CROP:可以使用均衡的缩放图像(保持图像原始比例),使图片的两个坐标(宽、高)都大于等于 相应的视图坐标(负的内边距),图像则位于视图的中央
imageView.setScaleType(ScaleType.CENTER_CROP);
listView = (ListView) getChildAt(1);
}
4 事件拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
downX = (int) ev.getX();
downY = (int) ev.getY();
}
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
int currentX = (int) ev.getX();
int currentY = (int) ev.getY();
// 确保是垂直滑动
if (Math.abs(currentY - downY) Math.abs(currentX - downX)) {
View childView = listView.getChildAt(listView
.getFirstVisiblePosition());
// 有两种情况需要拦截:
// 1 图片没有完全隐藏
// 2 图片完全隐藏,但是向下滑动,并且ListView滑动到顶部
if (getScrollY() != imageHeight
|| (getScrollY() == imageHeight && currentY - downY 0
&& childView != null && childView.getTop() == 0)) {
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
return true;
}
}
}
if (ev.getAction() == MotionEvent.ACTION_UP) {
recycleVelocityTracker();
}
return super.onInterceptTouchEvent(ev);
}
5 onTouchEvent的ACTION_MOVE处理
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
int currentX = (int) ev.getX();
int currentY = (int) ev.getY();
int deltyX = currentX - downX;
int deltyY = currentY - downY;
if (Math.abs(deltyY) Math.abs(deltyX)) {
if (deltyY 0) {
if (getScrollY() 0) {
if (getScrollY() - deltyY < 0) {
scrollBy(0, -getScrollY());
return true;
}
// 当图片没有完全显示,并且向下滑动时,继续整个view使图片可见
scrollBy(0, -deltyY);
} else {
// 当图片完全显示,并且向下滑动时,则不断的放大图片(通过改变ImageView)的高度
LayoutParams layoutParams = (LayoutParams) getChildAt(0)
.getLayoutParams();
layoutParams.height = layoutParams.height + deltyY / 2;
getChildAt(0).setLayoutParams(layoutParams);
}
} else {
// 当图片还处于放大状态,并且向上滑动时,继续不断的缩小图片的高度,使图片缩小
if (getChildAt(1).getTop() imageHeight) {
LayoutParams layoutParams = (LayoutParams) getChildAt(0)
.getLayoutParams();
layoutParams.height = layoutParams.height + deltyY / 2;
getChildAt(0).setLayoutParams(layoutParams);
} else {
// 当图片处于正常状态,并且向上滑动时,移动整个View,缩小图片的可见范围
if (getScrollY() - deltyY imageHeight) {
scrollBy(0, imageHeight - getScrollY());
return true;
}
scrollBy(0, -deltyY);
}
}
downY = currentY;
downX = currentX;
return true;
}
}
5 onTouchEvent的ACTION_UP处理
if (ev.getAction() == MotionEvent.ACTION_UP) {
// 当图片处于放大状态时松手,使图片缓慢的缩回到原来的状态
if (getChildAt(1).getTop() imageHeight) {
isAnimating = true;
ValueAnimator valueAnimator = ValueAnimator.ofInt(getChildAt(1)
.getTop(), imageHeight);
valueAnimator.setDuration(300);
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
LayoutParams layoutParams = (LayoutParams) getChildAt(0)
.getLayoutParams();
layoutParams.height = value;
getChildAt(0).setLayoutParams(layoutParams);
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimating = false;
}
});
valueAnimator.start();
}
// 当现在图片处于正常状态,并且图片没有完全隐藏,并且松手时滑动的速度大于可惯性滑动的最小值,让View产生惯性滑动效果
if (getChildAt(1).getTop() == imageHeight
&& getScrollY() != imageHeight) {
mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int velocityY = (int) mVelocityTracker.getYVelocity();
if (Math.abs(velocityY) mMinimumVelocity) {
fling(-velocityY);
}
recycleVelocityTracker();
}
总结
这里主要有两个学习的点
1 图片缩放的处理,事件的拦截
2 View的惯性滑动:主要是结合OverScroller的使用
以上就是本文的全部内容,希望对大家的学习有所帮助。
- 巧用 SecureCRT 实现复杂的 ssh 登录过程自动化
- pyDes 实现 Python 版的 DES 对称加密/解密
- 流水灯
- Chrome 自动化交互利器:用 tampermonkey 向页面注入自定义 Javascript
- 一次小折腾:PyCharm 调用 Cygwin Python 找不到 time、sys 等内置模块
- 网站数据统计分析之二:前端日志采集是与非
- Linux Shell 从入门到删除根目录跑路指南
- SSD Win8 系统盘 4K 无损对齐历险记
- 详解 MySQL 5.7 新的权限与安全问题
- Hive Lock 那些事儿
- Shell 黑科技之匿名函数实现任务并行化
- 文本编辑利器Notepad++ 10个强大而又鲜为人知的特性
- 记一次诡异的 ssh 互信免密码登录失败
- Linux下恶意文件大规模共性分析探讨
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- SQL Server 每日一题--解析天气预报员
- 未读消息(小红点),前端与 RabbitMQ实时消息推送实践,贼简单~
- 手把手教你用neo4j搭建简单关联图谱(基于家有儿女中的人物关系)
- c#中的静态本地方法
- C#加解密
- SQL Server 每日一题--解析老N的收入
- neo4j中导入数据的两种常用方式(千万级和亿级)
- Entity Framework Core 实现全局查询过滤
- Entity Framework Core 捕获数据库变动
- SQL Server 每日一题--解析产品
- Python绘制漫天的雪花,漫步天涯
- c#8内插逐字字符串增强功能
- EF Core 数据验证
- 网站优化,这些工具你一定用得着
- 一、了解Scrapy