本人做的项目是某传统行业的一款电商产品,项目中有的商品详情页需要和淘宝商品详情页类似的效果,就是实现toolbar和状态栏 更加页面的滚动实习透明度的渐变
其实和某宝还有点差距 ,毕竟 我们是在H5页面去做的这种效果,接下来我说说具体实现。
这个h5页 只有title bar (toolbar)是本地 然后下面是webview,通过重写webview 的onscrollChangedListener() 方法。而onscrollChangedListener 的权限是protected 所有只有继承Webview 如下
public class CustomWebview extends WebView {
public ScrollChangeListener mChangeListener;
public CustomWebview(Context context) {
super(context);
}
public CustomWebview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomWebview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomWebview(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mChangeListener != null) {
mChangeListener.onScrollChanged(l, t, oldl, oldt);
}
}
public void setOnScrollChangeListener(ScrollChangeListener listener) {
mChangeListener = listener;
}
interface ScrollChangeListener {
void onScrollChanged(int l, int t, int oldl, int oldt);
}
}
然后 在fragment里面实例化这个控件 ,因为我们的H5fragment是个基类 所以 就写了一个空的 方法 供子类继承重写
private void initWebViewScrollChangeListener() {
if (mWebView instanceof CustomWebview) {
((CustomWebview) mWebView)
.setOnScrollChangeListener(new CustomWebview.ScrollChangeListener() {
@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {
onWebViewScrollChanged(l, t, oldl, oldt);//这个是fragment里面的一个空的方法
}
});
}
}
这儿解释一下 我们架构 都是一个activity 嵌套一个fragment,所有的业务逻辑都在fragment里面去做。toolbar的操作是在activity里面进行的
activity的代码 一些说明我就写在代码的注释里面了
public class ShadowH5Activity extends H5Activity {
private ShadowH5Fragment mFlashBuyH5Fragment;
private SystemBarTintManager mTintManager;
private CommonTitleView mTitleView;// 虽然用的toolbar,但是在我们项目中他只是个容器,比如这个view就是 真正的一个有返回箭头 和title的view
//可以自定义view的样式 在这里 我就是操作的这个view整体background的透明度 ,
@Override
protected void onCreate(Bundle onSaveInstanceState) {
super.onCreate(onSaveInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//特别说明一下 沉浸式效果只有在sdk19以上的版本才有,以下的没有
showStatusBar();
}
}
@Override
public BaseFragment getFragment() {
mFlashBuyH5Fragment = (ShadowH5Fragment) Fragment.instantiate(this,
ShadowH5Fragment.class.getName(), getIntent().getExtras());
return mFlashBuyH5Fragment;
}
@Override
protected int getLayoutId() {
return R.layout.shadow_tool_bar_h5_fragment_activity;//下面会有布局的代码
}
@Override
protected void customizeToolbar(Toolbar toolbar) {
setToolbarMarginTop(toolbar);
}
/**
*
* @param alpha 0~255
*/ 背景的透明度
public void setTitleViewBacGroundAlpha(int alpha) {
if (mTitleView != null && mTitleView.getBackground() != null)
mTitleView.getBackground().setAlpha(alpha);
}
@Override
protected TitleContainer getMyTitleContainer() {
mTitleView = CommonTitleView.newInstance(this);//自定义一个view 不过 我还是复用的老的view 在这个 我想拿到这个view的对象 所以重写了
return mTitleView;
}
/**
*
* @param alpha 0~1 控制title的透明度
*/
public void setTitleAlpha(float alpha) {
if (mTitleView != null && mTitleView.getTitle() != null) {
mTitleView.getTitle().setAlpha(alpha);
}
}
/**
* 兼容性问题
*
* @param toolbar
*/
@TargetApi(19)
private void setToolbarMarginTop(Toolbar toolbar) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//前面说了,版本19以上 的会有状太栏 渐变的效果,因为我吧整个页面全屏之后
RelativeLayout.LayoutParams params =// statusBar 就隐藏了,但是我会把它show出来 ,此时toolbar和statusbar就会重叠,所以我给toolbar设置
new RelativeLayout.LayoutParams(toolbar.getLayoutParams());//marginTop的属性,正好距离顶部一个statusbar的高度,=
params.setMargins(0, getStatusBarHeight(), 0, 0);
toolbar.setLayoutParams(params);
}
}
@Override
protected void initWindow() {重写基类的方法 实现沉浸式statusbar 蓝色的
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
mTintManager = new SystemBarTintManager(this);
mTintManager.setStatusBarTintEnabled(true);
mTintManager.setTintColor(getResources().getColor(R.color.theme_blue));
}
}
/**
*
* @return 状态栏高度
*/
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public void setStatusBarAlpha(float statusBarAlpha) {
if (mTintManager != null) {
mTintManager.setTintAlpha(statusBarAlpha);
}
}
/**
* 隐藏状态栏
*/
private void hideStatusBar() {
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
getWindow().setAttributes(attrs);
}
/**
* 在全屏状态下 显示状态栏 (这种显示出来的statusbar 不会导致整个页面重绘)
*/
private void showStatusBar() {
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
getWindow().setAttributes(attrs);
}
}
fragment 的代码如下
public class ShadowH5Fragment extends H5Fragment {
private ShadowH5Activity mActivity;
private static final float SCROLL_LIMIT = 300f;//滑动的距离
private static final float sDEFAULT_ALPHA = 0;//默认的透明度
@Override
protected void onInflated(View contentView, Bundle savedInstanceState) {
super.onInflated(contentView, savedInstanceState);
initViewAlpha();
}
private void initViewAlpha() {
if (getActivity() != null) {
if (getActivity() instanceof ShadowH5Activity) {
mActivity = (ShadowH5Activity) getActivity();
mActivity.setTitleViewBacGroundAlpha((int) sDEFAULT_ALPHA);
mActivity.setTitleAlpha(sDEFAULT_ALPHA);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mActivity.setStatusBarAlpha(sDEFAULT_ALPHA);
}
}
}
}
@Override
protected void onWebViewScrollChanged(int l, int t, int oldl, int oldt) {
if (mActivity != null) {
float castT = t;
if (t < SCROLL_LIMIT) {
float progress = (castT / SCROLL_LIMIT);
progress = progress > 0 ? progress : 0;
mActivity.setTitleViewBacGroundAlpha((int) (progress * 255));
mActivity.setTitleAlpha(progress);
mActivity.setStatusBarAlpha(progress);
} else {
mActivity.setTitleViewBacGroundAlpha(255);
mActivity.setTitleAlpha(1);
mActivity.setStatusBarAlpha(1);
}
}
}
}