Android 沉浸式状态栏 头部可拉伸带有一键置顶功能
16lz
2021-01-23
一:实现沉浸式状态栏,头部可以拉伸,头部图片可下拉放大,带有一键置顶功能
先看看三个步骤:
1:在AndroidManifest.xml中设置Activity的属性为android:theme="@android:style/Theme.NoTitleBar"
2:在Layout的第一个布局中设置与头部的间隔(android:layout_marginTop="25dp",当然具体间隔多少需要根据自己的需求来)
3:在setContentView(R.layout.activity_userguide)之前super.onCreate(savedInstanceState)之后设置
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); }
1.主函数代码:
import android.graphics.Color;import android.os.Build;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.view.WindowManager;import android.widget.Button;import android.widget.ImageView;import android.widget.ListView;import android.widget.RelativeLayout;import android.widget.ScrollView;import android.widget.TextView;public class MainActivity extends AppCompatActivity { private NotifyingScrollView scrollview; private RelativeLayout topbar; private ImageView topimage; private ImageView iv_back; private TextView tv_title; private TextView textdemo; private Button button; private ListView listview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //沉浸式状态栏 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); } InfoData(); } public void InfoData(){ topbar = (RelativeLayout) findViewById(R.id.topbar); topimage = (ImageView) findViewById(R.id.topimage); iv_back = (ImageView) findViewById(R.id.iv_back); tv_title = (TextView) findViewById(R.id.tv_title); textdemo = (TextView) findViewById(R.id.textdemo); button = (Button) findViewById(R.id.button); listview = (ListView) findViewById(R.id.listview); listview.setAdapter(new MyAdapter(this)); scrollview = (NotifyingScrollView) findViewById(R.id.scrollview); //始终位于最顶部 scrollview.smoothScrollTo(0,0); //初始化标题栏相关的色值,为透明 topbar.getBackground().setAlpha(0); tv_title.setTextColor(Color.argb(0, 255, 255, 255)); textdemo.setBackgroundColor(Color.argb(0, 255, 255, 255)); scrollview.setOnScrollChangedListener(new NotifyingScrollView.OnScrollChangedListener() { @Override public void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt) { //滑动改变标题栏的透明度和文字透明度,图标 if (topimage == null) { return; } if(t < 0){ return; } //置顶操作 if (t > scrollview.getHeight()/2){ button.setVisibility(View.VISIBLE); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { scrollview.smoothScrollTo(0,0); } }); }else { button.setVisibility(View.GONE); } //获取滑动高度,做出对顶部导航栏的操作 int lHeight = 2*(topbar.getHeight()); if (t <= lHeight) { int progress = (int) (new Float(t) / new Float(lHeight) * 255); topbar.getBackground().setAlpha(progress); tv_title.setTextColor(Color.argb(progress, 255, 255, 255)); textdemo.setBackgroundColor(Color.argb(progress, 240, 240, 240)); iv_back.setImageResource(R.mipmap.icon_back_normal); } else { topbar.getBackground().setAlpha(255); tv_title.setTextColor(Color.argb(255, 255, 255, 255)); textdemo.setBackgroundColor(Color.argb(255, 232, 232, 232)); iv_back.setImageResource(R.mipmap.icon_back_pressed); } } }); }}
2.主函数布局:
<?xml version="1.0" encoding="utf-8"?>
3.自定义Scrollview:
import android.animation.ObjectAnimator;import android.animation.ValueAnimator;import android.content.Context;import android.os.Build;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.ScrollView;/** * 作者: yzp on 2016-10-09. * 邮箱: 15111424807@163.com * QQ: 486492302 * * 重写scrollview,以实现滑动效果 */public class NotifyingScrollView extends ScrollView implements View.OnTouchListener { // 记录首次按下位置 private float mFirstPosition = 0; // 是否正在放大 private Boolean mScaling = false; private View dropZoomView; private int dropZoomViewWidth; private int dropZoomViewHeight; private boolean mDisableEdgeEffects = true; public interface OnScrollChangedListener { void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt); } private OnScrollChangedListener mOnScrollChangedListener; public NotifyingScrollView(Context context) { super(context); } public NotifyingScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public NotifyingScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mOnScrollChangedListener != null) { mOnScrollChangedListener.onScrollChanged(this, l, t, oldl, oldt); } } public void setOnScrollChangedListener(OnScrollChangedListener listener) { mOnScrollChangedListener = listener; } @Override protected float getTopFadingEdgeStrength() { if (mDisableEdgeEffects && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return 0.0f; } return super.getTopFadingEdgeStrength(); } @Override protected float getBottomFadingEdgeStrength() { if (mDisableEdgeEffects && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return 0.0f; } return super.getBottomFadingEdgeStrength(); } //下拉放大效果处理 @Override protected void onFinishInflate() { super.onFinishInflate(); init(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } private void init() { setOverScrollMode(OVER_SCROLL_NEVER); if (getChildAt(0) != null) { ViewGroup vg = (ViewGroup) getChildAt(0); if (vg.getChildAt(0) != null) { dropZoomView = vg.getChildAt(0); setOnTouchListener(this); } } } /** * 下拉头部放大效果 * @param v * @param event * @return */ @Override public boolean onTouch(View v, MotionEvent event) { if (dropZoomViewWidth <= 0 || dropZoomViewHeight <= 0) { dropZoomViewWidth = dropZoomView.getMeasuredWidth(); dropZoomViewHeight = dropZoomView.getMeasuredHeight(); } switch (event.getAction()) { case MotionEvent.ACTION_UP: //手指离开后恢复图片 mScaling = false; replyImage(); 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; setZoom(1 + distance); return true; // 返回true表示已经完成触摸事件,不再处理 } return false; } // 回弹动画 (使用了属性动画) public void replyImage() { final float distance = dropZoomView.getMeasuredWidth() - dropZoomViewWidth; // 设置动画 ValueAnimator anim = ObjectAnimator.ofFloat(0.0F, 1.0F).setDuration((long) (distance * 0.7)); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float cVal = (Float) animation.getAnimatedValue(); setZoom(distance - ((distance) * cVal)); } }); anim.start(); } //缩放 public void setZoom(float s) { if (dropZoomViewHeight <= 0 || dropZoomViewWidth <= 0) { return; } ViewGroup.LayoutParams lp = dropZoomView.getLayoutParams(); //此处不处理头部某一边变宽// lp.width = (int) (dropZoomViewWidth + s); lp.height = (int) (dropZoomViewHeight * ((dropZoomViewWidth + s) / dropZoomViewWidth)); dropZoomView.setLayoutParams(lp); }}
4.适配器:
import android.content.Context;import android.support.v4.app.FragmentActivity;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;public class MyAdapter extends BaseAdapter { Context context; public MyAdapter(Context context) { // TODO Auto-generated constructor stub this.context=context; } @Override public int getCount() { return 15; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { View vi = convertView; vi = vi.inflate(context, R.layout.listview_text, null); return vi; }}
5.适配器布局:
<?xml version="1.0" encoding="utf-8"?>
二:Android沉浸式状态栏 + actionBar渐变 + scrollView顶部伸缩(拉伸时上下伸缩,左右不变)
(上图是参考图片,来自yanjunhui)
注意:沉浸式状态栏(API-Level 19, Android4.4 KitKat 之后加入的东西),而且在Api-Level 21版本中新增了一个属性(下面会说到)。所以,style文件应该声明三份:
values:
values-19:
values-V21
1.自定义TranslucentScrollView类:
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;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 colorRes 渐变的颜色 */ public void setTransColor(@ColorInt int colorRes) { this.transColor = colorRes; } /** * 设置渐变视图 * * @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); }}
2.主函数布局:
<?xml version="1.0" encoding="utf-8"?>
3.主函数逻辑:
import android.os.Bundle;import android.support.annotation.Nullable;import android.view.View;import test.com.base.BaseActivity;import test.com.impl.ActionBarClickListener;import test.com.widget.TranslucentActionBar;import test.com.widget.TranslucentScrollView;public class MainActivity extends BaseActivity implements ActionBarClickListener, TranslucentScrollView.TranslucentChangedListener { private TranslucentScrollView translucentScrollView; private TranslucentActionBar actionBar; private View zoomView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { actionBar = (TranslucentActionBar) findViewById(R.id.actionbar); //初始actionBar actionBar.setData("测试", 0, null, 0, null, null); //开启渐变 actionBar.setNeedTranslucent(); //设置状态栏高度 actionBar.setStatusBarHeight(getStatusBarHeight()); translucentScrollView = (TranslucentScrollView) findViewById(R.id.pullzoom_scrollview); //设置透明度变化监听 translucentScrollView.setTranslucentChangedListener(this); //关联需要渐变的视图 translucentScrollView.setTransView(actionBar); //设置ActionBar键渐变颜色 translucentScrollView.setTransColor(getResources().getColor(R.color.orange_dft)); zoomView = findViewById(R.id.lay_header); //关联伸缩的视图 translucentScrollView.setPullZoomView(zoomView); } @Override public void onLeftClick() { } @Override public void onRightClick() { } @Override public void onTranslucentChanged(int transAlpha) { actionBar.tvTitle.setVisibility(transAlpha > 48 ? View.VISIBLE : View.GONE); }}
4.ActionBarClickListener
public interface ActionBarClickListener { void onLeftClick(); void onRightClick();}
5.TranslucentActionBar
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 */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(); } }); } }}
6.actionbar_trans布局
<?xml version="1.0" encoding="utf-8"?>
下载地址:https://github.com/yanjunhui2014/TranslucentScrollView
更多相关文章
- Android自定义Toast的时长、位置、及显示的View
- android 6.0锁屏界面时间位置修改
- android GridView(网格视图)
- android基础控件(4)GridView实现网格视图
- android 修改AVD的存放位置
- Android的Activity切换动画特效库SwitchLayout,视图切换动画库,媲
- Android中水波纹使用之自定义视图实现
- android控制显示和隐藏视图或控件的操作