Android沉浸式状态栏 + actionBar渐变 + scrollView顶部伸缩效果
作者:yanjunhui2011 发布时间:2021-09-12 01:04:16
闲话不多说,直接上图。
给大家讲讲我的编程思想吧。
第一部分:沉浸式状态栏(API-Level 19, Android4.4 KitKat 之后加入的东西),而且在Api-Level 21版本中新增了一个属性(下面会说到)。所以,style文件应该声明三份。
values
<style name="TranslucentTheme" parent="@style/AppTheme">
</style>values-19
<style name="TranslucentTheme" parent="@style/AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
</style>values-V21
<style name="TranslucentTheme" parent="@style/AppTheme">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
<!-- v-21 中新增的属性 -->
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
至于以上属性的含义及使用方式,就不多做解释了。详细可参见 https://www.jb51.net/article/104485.htm
第二部分:actionBar渐变
因为要实现actionBar渐变,所以我没有使用系统的actionBar。而是自定义了一个继承自LinearLayout的ViewGroup。
直接给各位看代码
package test.com.widget;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import test.com.R;
import test.com.impl.ActionBarClickListener;
/**
* 支持渐变的 actionBar
* Created by 晖仔(Milo) on 2016/12/28.
* email:303767416@qq.com
*/
public final class TranslucentActionBar extends LinearLayout {
private View layRoot;
private View vStatusBar;
private View layLeft;
private View layRight;
public TextView tvTitle;
private TextView tvLeft;
private TextView tvRight;
private View iconLeft;
private View iconRight;
public TranslucentActionBar(Context context) {
this(context, null);
}
public TranslucentActionBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TranslucentActionBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init() {
setOrientation(HORIZONTAL);
View contentView = inflate(getContext(), R.layout.actionbar_trans, this);
layRoot = contentView.findViewById(R.id.lay_transroot);
vStatusBar = contentView.findViewById(R.id.v_statusbar);
tvTitle = (TextView) contentView.findViewById(R.id.tv_actionbar_title);
tvLeft = (TextView) contentView.findViewById(R.id.tv_actionbar_left);
tvRight = (TextView) contentView.findViewById(R.id.tv_actionbar_right);
iconLeft = contentView.findViewById(R.id.iv_actionbar_left);
iconRight = contentView.findViewById(R.id.v_actionbar_right);
}
/**
* 设置状态栏高度
*
* @param statusBarHeight
*/
public void setStatusBarHeight(int statusBarHeight) {
ViewGroup.LayoutParams params = vStatusBar.getLayoutParams();
params.height = statusBarHeight;
vStatusBar.setLayoutParams(params);
}
/**
* 设置是否需要渐变
*/
public void setNeedTranslucent() {
setNeedTranslucent(true, false);
}
/**
* 设置是否需要渐变,并且隐藏标题
*
* @param translucent
*/
public void setNeedTranslucent(boolean translucent, boolean titleInitVisibile) {
if (translucent) {
layRoot.setBackgroundDrawable(null);
}
if (!titleInitVisibile) {
tvTitle.setVisibility(View.GONE);
}
}
/**
* 设置标题
*
* @param strTitle
*/
public void setTitle(String strTitle) {
if (!TextUtils.isEmpty(strTitle)) {
tvTitle.setText(strTitle);
} else {
tvTitle.setVisibility(View.GONE);
}
}
/**
* 设置数据
*
* @param strTitle
* @param resIdLeft
* @param strLeft
* @param resIdRight
* @param strRight
* @param listener
*/
public void setData(String strTitle, int resIdLeft, String strLeft, int resIdRight, String strRight, final ActionBarClickListener listener) {
if (!TextUtils.isEmpty(strTitle)) {
tvTitle.setText(strTitle);
} else {
tvTitle.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(strLeft)) {
tvLeft.setText(strLeft);
tvLeft.setVisibility(View.VISIBLE);
} else {
tvLeft.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(strRight)) {
tvRight.setText(strRight);
tvRight.setVisibility(View.VISIBLE);
} else {
tvRight.setVisibility(View.GONE);
}
if (resIdLeft == 0) {
iconLeft.setVisibility(View.GONE);
} else {
iconLeft.setBackgroundResource(resIdLeft);
iconLeft.setVisibility(View.VISIBLE);
}
if (resIdRight == 0) {
iconRight.setVisibility(View.GONE);
} else {
iconRight.setBackgroundResource(resIdRight);
iconRight.setVisibility(View.VISIBLE);
}
if (listener != null) {
layLeft = findViewById(R.id.lay_actionbar_left);
layRight = findViewById(R.id.lay_actionbar_right);
layLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onLeftClick();
}
});
layRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onRightClick();
}
});
}
}
}
下面是actionbar_trans.xml的代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/lay_transroot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:orientation="vertical">
<View
android:id="@+id/v_statusbar"
android:layout_width="match_parent"
android:layout_height="1.0dp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/lay_actionbar_left"
android:layout_width="100dp"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_actionbar_left"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@mipmap/ic_left_light"
android:visibility="gone" />
<TextView
android:id="@+id/tv_actionbar_left"
style="@style/text_white"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/iv_actionbar_left"
android:gravity="center_vertical"
android:maxLength="2"
android:singleLine="true"
android:text="返回"
android:visibility="gone" />
</RelativeLayout>
<TextView
android:id="@+id/tv_actionbar_title"
style="@style/text_white"
android:layout_centerInParent="true"
android:text="标题"
android:textSize="16sp" />
<RelativeLayout
android:id="@+id/lay_actionbar_right"
android:layout_width="100dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:gravity="right"
android:orientation="horizontal">
<View
android:id="@+id/v_actionbar_right"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:visibility="gone" />
<TextView
android:id="@+id/tv_actionbar_right"
style="@style/text_white"
android:layout_height="match_parent"
android:layout_marginRight="10dp"
android:layout_toLeftOf="@+id/v_actionbar_right"
android:gravity="center_vertical|right"
android:singleLine="true"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
这里我即没有用到 android:fitsSystemWindows="true" 属性,也没有用到 StatusBarUtils ,因为我发现使用的时候很容易造成兼容问题。
所以,我的做法是声明了一个高度为0.0dp的 statusbar,背景为透明,然后获取状态栏高度并赋值到它上,来实现兼容。事实证明,这样做的兼容效果最好。
获取状态栏高度代码:
/**
* 获取状态栏高度
*
* @return
*/
public int getStatusBarHeight() {
//获取status_bar_height资源的ID
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
//根据资源ID获取响应的尺寸值
return getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
设置 statusbar高度:
/**
* 设置状态栏高度
*
* @param statusBarHeight
*/
public void setStatusBarHeight(int statusBarHeight) {
ViewGroup.LayoutParams params = vStatusBar.getLayoutParams();
params.height = statusBarHeight;
vStatusBar.setLayoutParams(params);
}
开启渐变:
/**
* 设置是否需要渐变
*/
public void setNeedTranslucent() {
setNeedTranslucent(true, false);
}
/**
* 设置是否需要渐变,并且隐藏标题
*
* @param translucent
*/
public void setNeedTranslucent(boolean translucent, boolean titleInitVisibile) {
if (translucent) {
layRoot.setBackgroundDrawable(null);
}
if (!titleInitVisibile) {
tvTitle.setVisibility(View.GONE);
}
}
第三步:实现ScrollView顶部伸缩
到了这里,必须得说一下,因为是个人项目中用到,所以并没有把功能做的很强大,本人都是以最简单、有效的方式实现的。所以,代码并不像gitHub上那些被下载很多次的开源项目一样,有很高的扩展性。
时间关系,我直接贴代码吧,代码里我都写了注释的。
package test.com.widget;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.ColorInt;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ScrollView;
import test.com.R;
import test.com.utils.SizeUtils;
/**
* Created by 晖仔(Milo) on 2017/2/13.
* email:303767416@qq.com
*/
public class TranslucentScrollView extends ScrollView {
static final String TAG = "TranslucentScrollView";
//伸缩视图
private View zoomView;
//伸缩视图初始高度
private int zoomViewInitHeight = 0;
// 记录首次按下位置
private float mFirstPosition = 0;
// 是否正在放大
private Boolean mScaling = false;
//渐变的视图
private View transView;
//渐变颜色
private int transColor = Color.WHITE;
//渐变开始位置
private int transStartY = 50;
//渐变结束位置
private int transEndY = 300;
//渐变开始默认位置,Y轴,50dp
private final int DFT_TRANSSTARTY = 50;
//渐变结束默认位置,Y轴,300dp
private final int DFT_TRANSENDY = 300;
private TranslucentScrollView.TranslucentChangedListener translucentChangedListener;
public interface TranslucentChangedListener {
/**
* 透明度变化,取值范围0-255
*
* @param transAlpha
*/
void onTranslucentChanged(int transAlpha);
}
public TranslucentScrollView(Context context) {
super(context);
}
public TranslucentScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TranslucentScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setTranslucentChangedListener(TranslucentScrollView.TranslucentChangedListener translucentChangedListener) {
this.translucentChangedListener = translucentChangedListener;
}
/**
* 设置伸缩视图
*
* @param zoomView
*/
public void setPullZoomView(View zoomView) {
this.zoomView = zoomView;
zoomViewInitHeight = zoomView.getLayoutParams().height;
if (zoomViewInitHeight == LayoutParams.MATCH_PARENT || zoomViewInitHeight == WindowManager.LayoutParams.WRAP_CONTENT) {
zoomView.post(new Runnable() {
@Override
public void run() {
zoomViewInitHeight = TranslucentScrollView.this.zoomView.getHeight();
}
});
}
}
/**
* 设置渐变视图
*
* @param transView 渐变的视图
*/
public void setTransView(View transView) {
setTransView(transView, getResources().getColor(R.color.colorPrimary), SizeUtils.dip2px(getContext(), DFT_TRANSSTARTY), SizeUtils.dip2px(getContext(), DFT_TRANSENDY));
}
/**
* 设置渐变视图
*
* @param transView 渐变的视图
* @param transColor 渐变颜色
* @param transEndY 渐变结束位置
*/
public void setTransView(View transView, @ColorInt int transColor, int transStartY, int transEndY) {
this.transView = transView;
//初始视图-透明
this.transView.setBackgroundColor(ColorUtils.setAlphaComponent(transColor, 0));
this.transStartY = transStartY;
this.transEndY = transEndY;
this.transColor = transColor;
if (transStartY > transEndY) {
throw new IllegalArgumentException("transStartY 不得大于 transEndY .. ");
}
}
/**
* 获取透明度
*
* @return
*/
private int getTransAlpha() {
float scrollY = getScrollY();
if (transStartY != 0) {
if (scrollY <= transStartY) {
return 0;
} else if (scrollY >= transEndY) {
return 255;
} else {
return (int) ((scrollY - transStartY) / (transEndY - transStartY) * 255);
}
} else {
if (scrollY >= transEndY) {
return 255;
}
return (int) ((transEndY - scrollY) / transEndY * 255);
}
}
/**
* 重置ZoomView
*/
private void resetZoomView() {
final ViewGroup.LayoutParams lp = zoomView.getLayoutParams();
final float h = zoomView.getLayoutParams().height;// ZoomView当前高度
// 设置动画
ValueAnimator anim = ObjectAnimator.ofFloat(0.0F, 1.0F).setDuration(200);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float cVal = (Float) animation.getAnimatedValue();
lp.height = (int) (h - (h - zoomViewInitHeight) * cVal);
zoomView.setLayoutParams(lp);
}
});
anim.start();
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
int transAlpha = getTransAlpha();
if (transView != null) {
Log.d(TAG, "[onScrollChanged .. in ], 透明度 == " + transAlpha);
transView.setBackgroundColor(ColorUtils.setAlphaComponent(transColor, transAlpha));
}
if (translucentChangedListener != null) {
translucentChangedListener.onTranslucentChanged(transAlpha);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (zoomView != null) {
ViewGroup.LayoutParams params = zoomView.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
//手指离开后恢复图片
mScaling = false;
resetZoomView();
break;
case MotionEvent.ACTION_MOVE:
if (!mScaling) {
if (getScrollY() == 0) {
mFirstPosition = event.getY();
} else {
break;
}
}
int distance = (int) ((event.getY() - mFirstPosition) * 0.6);
if (distance < 0) {
break;
}
mScaling = true;
params.height = zoomViewInitHeight + distance;
Log.d(TAG, "params.height == " + params.height + ", zoomViewInitHeight == " + zoomViewInitHeight + ", distance == " + distance);
zoomView.setLayoutParams(params);
return true;
}
}
return super.onTouchEvent(event);
}
}
总结
以上所述是小编给大家介绍的Android沉浸式状态栏 + actionBar渐变 + scrollView顶部伸缩网站的支持!
来源:http://blog.csdn.net/yanjunhui2011/article/details/55190456
猜你喜欢
- 这一篇网络爬虫的实现就要联系上大数据了。在前两篇java实现网络爬虫和heritrix实现网络爬虫的基础上,这一次是要完整的做一次数据的收集
- 需求:类似医院或者商场,大屏幕无限轮播item (广告词/广告图…),供大家参考,具体内容如下代码如下/** * Created by Xi
- Lombok简介和其他语言相比,Java经常因为不必要的冗长被批评。Lombok提供了一系列注解用以在后台生成模板代码,将其从你的类中删除,
- TabHost组件可以在界面中存放多个选项卡, 很多软件都使用了改组件进行设计。一、基础知识TabWidget : 该组件就是TabHost
- app_main上一篇文章:# Android 10 启动分析之servicemanager篇 (二)在init篇中有提到,init进程会在
- Android setButtonDrawable()的兼容问题解决办法setButtonDrawable()的兼容问题API1
- Java中文件与目录管理目录是管理文件的特殊机制,同类文件保存在同一个目录下不仅可以简化文件管理,而且还可以提高工作效率。Java 语言在
- 本文实例为大家分享了android实现倒计时功能的具体代码,供大家参考,具体内容如下【思路】:通过 timer 执行周期延时的任务,hand
- 知识点回顾封装封装(有时称为数据隐藏)是与对象有关的一个重要概念。从形式上来看,封装不过是将数据和行为组合在一个包中,并对对象的使用者隐藏了
- Android 应用冷启动时,需要从Application开始启动,加载时间就会比较长,这段时间里,用户所能看到的就是”白屏“(这是因为默认
- 生命太短暂,不要去做一些根本没有人想要的东西。本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术
- fopen(打开文件)相关函数 open,fclose表头文件 #include<stdio.h>定义函数 FILE * fop
- 1.下载JRebel and XRebel for Intellij插件2. 激活请查看这个文章http://www.cicoding.cn
- 自动登录,是为了帮助用户多次使用这个网页时,不用再次输入用户名和密码就可以登录。自动登录是指用户将用户的登录信息,人,保存到本地的文件中Co
- 目录引言命名规则代码排版1.代码缩进对齐2.遇到分号换行3.大括号、括号等成对出现4.加上注释Java注释注释的作用注释的3种类型给代码加上
- 前言在实际的开发中,当我们完成了一个apk,一般都是英语和中文简体这两种语语言,如果发布了,则需要把字符转换给翻译公司,让他们帮忙翻译,一般
- 步骤:1、遍历D盘Source文件夹找出所有名称包含LTE的文件,文件路径存放到List<string>中2、遍历List<
- 问题学习完maven后,用maven创建了一个web项目,然后在这个web项目中创建了一个java文件夹并标记这个目录为源码根目录,当我准备
- 今天在APP中增加一个添加项目的功能,项目的主键为整数,要让它自增长。既然要自增长,那么在代码里面就不用给id字段赋值。但是调试的时候发现不
- 本文实例为大家分享了WPF实现背景灯光随鼠标闪动的具体代码,供大家参考,具体内容如下实现效果如下:思路:将容器分割成组合三角形Path,鼠标