热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android沉浸式状态栏+actionBar渐变+scrollView顶部伸缩

闲话不多说,直接上图。给大家讲讲我的编程思想吧。第一部分:沉浸式状态栏(API-Level19,Android4.4KitKat之后加入的东西),而且在Api-Level21版本中新增了一个

闲话不多说,直接上图。




给大家讲讲我的编程思想吧。

第一部分:沉浸式状态栏(API-Level 19, Android4.4 KitKat 之后加入的东西),而且在Api-Level 21版本中新增了一个属性(下面会说到)。所以,style文件应该声明三份。




values

values-19

values-V21


至于以上属性的含义及使用方式,就不多做解释了。详细可参见 http://blog.csdn.net/fan7983377/article/details/51604657


第二部分: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的代码


android:id="@+id/lay_transroot"
android:layout_
android:layout_
android:background="@color/colorPrimary"
android:orientation="vertical">

android:id="@+id/v_statusbar"
android:layout_
android:layout_ />

android:layout_
android:layout_
android:orientation="vertical">

android:id="@+id/lay_actionbar_left"
android:layout_
android:layout_
android:orientation="horizontal">

android:id="@+id/iv_actionbar_left"
android:layout_
android:layout_
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@mipmap/ic_left_light"
android:visibility="gone" />

android:id="@+id/tv_actionbar_left"

android:layout_
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" />


android:id="@+id/tv_actionbar_title"

android:layout_centerInParent="true"
android:text="标题"
android:textSize="16sp" />

android:id="@+id/lay_actionbar_right"
android:layout_
android:layout_
android:layout_alignParentRight="true"
android:gravity="right"
android:orientation="horizontal">

android:id="@+id/v_actionbar_right"
android:layout_
android:layout_
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:visibility="gone" />

android:id="@+id/tv_actionbar_right"

android:layout_
android:layout_marginRight="10dp"
android:layout_toLeftOf="@+id/v_actionbar_right"
android:gravity="center_vertical|right"
android:singleLine="true"
android:visibility="gone" />




这里我即没有用到 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);
}

}


如有问题,欢迎留言。

 

资源CSDN下载地址:还没上传,要等一下。

资源GitHub下载地址:https://github.com/yanjunhui2014/TranslucentScrollView


原创不易,转载请附上本文地址:





推荐阅读
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 今天就跟大家聊聊有关怎么在Android应用中实现一个换肤功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根 ... [详细]
  • 详解Android  自定义UI模板设计_由浅入深
    学习安卓已有一些日子,前段时间整理了不少笔记,但是发现笔记不变分享与携带。今天开始整理博客,全当是与大家分享交流与自身学习理解的过程吧。结合最近在做的一个新闻类app及学习中的问题,一点一点整理一下, ... [详细]
  • 第一步:PyQt4Designer设计程序界面该部分设计类同VisvalStudio内的设计,改下各部件的objectName!设计 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 解决文件名过长下载失败问题的jQuery方案
    本文介绍了使用jQuery解决文件名过长导致下载失败的问题。原方案中存在文件名部分丢失的问题,通过动态生成隐藏域表单并提交的方式来解决。详细的解决方案和代码示例在文章中给出。 ... [详细]
  • WPF开发心率检测大数据曲线图的高性能实现方法
    本文介绍了在WPF开发中实现心率检测大数据曲线图的高性能方法。作者尝试过使用Canvas和第三方开源库,但性能和功能都不理想。最终作者选择使用DrawingVisual对象,并结合局部显示的方式实现了自己想要的效果。文章详细介绍了实现思路和具体代码,对于不熟悉DrawingVisual的读者可以去微软官网了解更多细节。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 通过Anaconda安装tensorflow,并安装运行spyder编译器的完整教程
    本文提供了一个完整的教程,介绍了如何通过Anaconda安装tensorflow,并安装运行spyder编译器。文章详细介绍了安装Anaconda、创建tensorflow环境、安装GPU版本tensorflow、安装和运行Spyder编译器以及安装OpenCV等步骤。该教程适用于Windows 8操作系统,并提供了相关的网址供参考。通过本教程,读者可以轻松地安装和配置tensorflow环境,以及运行spyder编译器进行开发。 ... [详细]
author-avatar
我是爱琴白痴_935
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有