Android实现京东上滑效果
作者:qingwangwang 发布时间:2021-10-11 07:27:11
本文实例为大家分享了Android实现京东上滑效果的具体代码,供大家参考,具体内容如下
前言:
现在很多app首页的结构都有头部广告,上滑固定toolbar及侧滑广告位等展示,典型的比如招商银行app,支付宝、哈罗单车、京东、苏宁金融也有类似的效果。具体如下,左侧为有广告位存在的情况,右侧无顶部广告位的样式:
效果说明:头部广告一般在节假日有活动的时候展示,页面上滑会有固定标题栏展示,靠底部右侧有一个小的广告位,滑动主屏幕时,广告位会向右侧收起,屏幕不滚动时,广告位显示。本文旨在为实现这种效果提供一种方式,欢迎有其他想法的小伙伴评论交流,接下来将分三块分别实现顶部广告位,滑动固定toolbar及侧滑广告位效果。
顶部广告位:
分析:有广告位图片和没广告位图片的区别在于下方白色内容区域在图片下方还是在顶部4个功能项的下方,一种方式:根据是否有广告位动态调整margin高度;方式二:使用约束布局,根据情况改变白色区域内容相对谁来布局
实现:
这里我们使用第二种方式实现:
外层父布局为ConstraintLayout,里面内容包含三部分:
1. 底部背景ImageView控件A,有图片时设置src,无图时设置background;
2. 四个功能选项部分B,即无图时白色区域的约束对象;
3. 白色内容区域C,无图时约束对象为B,有图时约束对象为A;
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_header"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_bg_header"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="@drawable/shape_gradient_yellow"
android:contentDescription="@null"
android:scaleType="fitXY"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/ll_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="50dp"
android:layout_marginEnd="12dp"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<EditText
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_weight="1"
android:background="@drawable/shape_edit_text_stroke_white"
android:drawableStart="@drawable/vector_search"
android:drawablePadding="4dp"
android:drawableTint="@color/color_icon"
android:hint="请输入内容"
android:importantForAutofill="no"
android:paddingStart="8dp"
android:textColorHint="@color/color_icon"
android:textSize="14sp"
tools:ignore="TextFields" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:contentDescription="@null"
android:src="@drawable/vector_custom_service"
android:tint="@color/color_icon" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:contentDescription="@null"
android:src="@drawable/vector_message"
android:tint="@color/color_icon" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:orientation="horizontal"
android:paddingTop="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ll_search">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="@drawable/vector_code"
android:drawablePadding="8dp"
android:gravity="center_horizontal"
android:text="收/付款"
android:textColor="@color/color_white" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="@drawable/vector_shopping"
android:drawablePadding="8dp"
android:gravity="center_horizontal"
android:text="购物"
android:textColor="@color/color_white" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="@drawable/vector_setting"
android:drawablePadding="8dp"
android:gravity="center_horizontal"
android:text="设置"
android:textColor="@color/color_white" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="@drawable/vector_function"
android:drawablePadding="8dp"
android:gravity="center_horizontal"
android:text="全部功能"
android:textColor="@color/color_white" />
</LinearLayout>
<include
android:id="@+id/ll_services"
layout="@layout/layout_services"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ll_header" />
</androidx.constraintlayout.widget.ConstraintLayout>
展示广告位的情况下
ivBgHeader.setBackgroundResource(0);
ivBgHeader.setImageResource(R.mipmap.ic_ad_banner);
ivBgHeader.setOnClickListener(v -> Toast.makeText(getActivity(), "拍一拍", Toast.LENGTH_SHORT).show());
ConstraintSet c = new ConstraintSet();
c.clone(clHeader);
c.connect(llServices.getId(), ConstraintSet.TOP, ivBgHeader.getId(), ConstraintSet.BOTTOM, Utils.dip2pixel(getActivity(), 20));
c.applyTo(clHeader);
不展示广告位情况下:
ivBgHeader.setBackgroundResource(R.drawable.shape_gradient_yellow);
ivBgHeader.setImageResource(0);
ivBgHeader.setOnClickListener(null);
ConstraintSet c = new ConstraintSet();
c.clone(clHeader);
c.connect(llServices.getId(), ConstraintSet.TOP, llHeader.getId(), ConstraintSet.BOTTOM, Utils.dip2pixel(getActivity(), 20));
c.applyTo(clHeader);
侧滑广告位:
分析:首页的滑动布局为NestedScrollView控件实现的,NestedScrollView并没有像RecyclerView一样提供滑动状态的监听,所以关于滑动状态需要我们去判断,更准确可以说是监听状态的改变结果,而不是监听状态的过程,状态结果分两种:静止和滑动。NestedScrollView提供了onScrollChanged回调方法,在内部View滑动时会走到这个回调,所以走这个回调肯定是滑动中状态,如何判断静止状态呢?通常是使用定时器或是handler发送消息的方式去监听。
实现:
自定义View继承NestedScrollView,在内部将状态提供给外部去使用
public class ObservableScrollView extends NestedScrollView {
public static final int STATE_IDLE = 1;
public static final int STATE_SCROLL = 2;
public int currentState = STATE_IDLE;
private boolean isOnActionDown = false;
private ScrollStateChangeListener scrollStateChangeListener;
private Handler mHandler;
private static final int MSG_IS_SCROLL = 1;
public ObservableScrollView(@NonNull Context context) {
this(context, null);
}
public ObservableScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ObservableScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (currentState == STATE_SCROLL) {
currentState = STATE_IDLE;
if (null != scrollStateChangeListener) {
scrollStateChangeListener.onScrollChange(ObservableScrollView.this, currentState);
}
}
}
};
}
@Override
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if (isOnActionDown)
return;
mHandler.removeCallbacksAndMessages(null);
mHandler.sendEmptyMessageDelayed(MSG_IS_SCROLL, 500);
setStatus();
}
private void setStatus() {
if (currentState == STATE_IDLE) {
currentState = STATE_SCROLL;
if (null != scrollStateChangeListener) {
scrollStateChangeListener.onScrollChange(this, currentState);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isOnActionDown = false;
mHandler.sendEmptyMessageDelayed(MSG_IS_SCROLL, 500);
break;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
mHandler.removeCallbacksAndMessages(null);
setStatus();
isOnActionDown = true;
break;
}
return super.onTouchEvent(ev);
}
public void addOnScrollChangeListener(ScrollStateChangeListener scrollStateChangeListener) {
this.scrollStateChangeListener = scrollStateChangeListener;
}
public interface ScrollStateChangeListener {
void onScrollChange(ObservableScrollView view, int newState);
}
public void onDestroy() {
if (null != mHandler) {
mHandler.removeCallbacksAndMessages(null);
}
}
}
外部使用:
scrollView.addOnScrollChangeListener(new ObservableScrollView.ScrollStateChangeListener() {
@Override
public void onScrollChange(ObservableScrollView view, int newState) {
if (newState == STATE_IDLE) {
ivSideScroll.animate().translationX(0);
} else {
ivSideScroll.animate().translationX(200);
}
}
});
固定顶部效果:
分析:监听scrollView滑动变化量,分别在上滑和下滑时做固定内容部分的透明度值变化
实现:
scrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
@Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
// 向上滑动,超过100像素则透明度开始由0 -> 1
if (scrollY - oldScrollY > 0) {
float alpha = Math.min(1, (scrollY - 100) / 50f);
llFixedHeader.setAlpha(alpha);
}
// 向下滑动,小于100像素则透明度开始 1 -> 0
if (scrollY - oldScrollY < 0) {
float alpha = Math.max(0, (scrollY - 100) / 50f);
llFixedHeader.setAlpha(alpha);
}
}
});
最终实现效果:
来源:https://blog.csdn.net/qingwangwang/article/details/108920754
猜你喜欢
- 一、一级缓存二级缓存的概念解释(1)一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓
- 本文实例讲述了Android TextView中文字通过SpannableString设置属性的方法。分享给大家供大家参考,具体如下:在An
- 缘起工作时使用java开发服务器后台,用Jersey写Restful接口,发现有一个Post方法始终获取不到参数,查了半天,发现时获取参数的
- 废话不多说了,直接给大家贴关键代码了。具体代码如下所示:using System;using System.Collections.Gene
- 我在5月份的时候就申请了洞态IAST企业版内测,算是比较早的一批用户了。聊聊几个我比较在意的问题,比如API接口覆盖率、第三方开源组件检测以
- Kotlin基础教程之Run,标签Label,函数Function-Type在Java中可以使用{}建立一个匿名的代码块,代码块会被正常的执
- C# FileStream类在 C# 语言中文件读写流使用 FileStream 类来表示,FileStream 类主要用于文件的读写,不仅
- 前言通常在工作中比较常用到的Microsoft Word是属于国外的文档内容编辑软件,其编译技术均属国外。而OFD是一种我国的自主文档格式,
- 前言:在日常的代码开发中,此处相信每个开发人员对代码质量都是高要求,有自己的一套代码规范,但是我们不是单独作战,往往大家都是团队作战,人是最
- MyCat一个彻底开源的,面向企业应用开发的大数据库集群。基于阿里开源的Cobar产品而研发。能满足数据库数据大量存储;提高了查询性能。文章
- 表单代码<!DOCTYPE html><html lang="en" xmlns="http
- 看代码吧~package com.mtpc.admin.controller.exportSql;import ch.qos.logback
- 在《Android Handler之消息循环的深入解析》中谈到了Handler是用于操作线程内部的消息队列,所以Handler可以用来线程间
- 在Java的学习中,涉及到两个系统环境变量path和classpath一. path环境变量path环境变量是系统环境变量的一种,它用于保存
- 前言在RequestMappingHandlerAdapter对request进行了适配,并且调用了目标handler之后,其会返回一个Mo
- 前言加密配置是一个很常见的需求,在spring boot生态中,已经有非常多的第三方starter实现了,博主所在公司也有这种强制要求,一些
- 前言SpringBoot是我们经常使用的框架,那么你能不能针对SpringBoot实现自动配置做一个详细的介绍。如果可以的话,能不能画一下实
- 本文实例为大家分享了java实现五子棋程序的具体代码,供大家参考,具体内容如下知识点1、Swing 编程2、ImageIO 类的使用3、图片
- 一、SpringMvc概述SpringMVC是一个基于MVC设计模式的WEB层框架。SpringMVC设计模式:MVC,全名是(Model
- 要想充分理解C# out和ref,必须先明确如下两个概念(对值类型与引用类型掌握比较好的,可以跳过“一、明确两个基本概念”)一、明确两个基本