话不多说先看效果:
个人实现效果图:
前几天小米手机应用商店更新,看到这样的效果,之后看到其他app也有这样的效果,闲来无事搞一下。
首先怎么实现呢?
思路:不考虑滑动,先要实现全屏,而且上方状态栏显示,之后重写Scrollview,监听滑动事件,当滑动一定距离时不断更新action bar的透明度。
主要代码:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
setContentView(R.layout.activity_nac);
if (Build.VERSION.SDK_INT >= 21) {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
}
然后就是重写ScrollView:
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.util.LogPrinter;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;
/**
* Created by ZHL on 2016/12/19.
*/
public class FadingScrollView extends ScrollView {
private static String TAG = "-----------FadingScrollView----------";
//渐变view
private View fadingView;
//滑动view的高度,如果这里fadingHeightView是一张图片,
// 那么就是这张图片上滑至完全消失时action bar 完全显示,
// 过程中透明度不断增加,直至完全显示
private View fadingHeightView;
private int oldY;
//滑动距离,默认设置滑动500 时完全显示,根据实际需求自己设置
private int fadingHeight = 500;
public FadingScrollView(Context context) {
super(context);
}
public FadingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FadingScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setFadingView(View view){this.fadingView = view;}
public void setFadingHeightView(View v){this.fadingHeightView = v;}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(fadingHeightView != null)
fadingHeight = fadingHeightView.getMeasuredHeight();
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
// l,t 滑动后 xy位置,
// oldl lodt 滑动前 xy 位置-----
float fading = t>fadingHeight ? fadingHeight : (t > 30 ? t : 0);
updateActionBarAlpha( fading / fadingHeight);
}
void updateActionBarAlpha(float alpha){
try {
setActionBarAlpha(alpha);
} catch (Exception e) {
e.printStackTrace();
}
}
public void setActionBarAlpha(float alpha) throws Exception{
if(fadingView==null){
throw new Exception("fadingView is null...");
}
fadingView.setAlpha(alpha);
}
}
布局文件:
activity 使用:
public class NacActivity extends AppCompatActivity {
private View layout;
private FadingScrollView fadingScrollView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
setContentView(R.layout.activity_nac);
if (Build.VERSION.SDK_INT >= 21) {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
getWindow().setNavigationBarColor(Color.TRANSPARENT);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
layout = findViewById(R.id.nac_layout);
layout.setAlpha(0);
fadingScrollView = (FadingScrollView)findViewById(R.id.nac_root);
fadingScrollView.setFadingView(layout);
fadingScrollView.setFadingHeightView(findViewById(R.id.nac_image));
}
}
说一下上方所谓的action bar,这里并没有直接使用actionbar,而是使用自己的布局,因为使用action bar ,就要在activity中对它进行声明设置一些属性,而要实现状态栏透明 这样的效果,代码中已经设置actionbar hide,可能会起冲突,所以在写demo时就直接放弃了actionbar。
这样就大功告成了,如果有说的不正确的地方,欢迎留言一起讨论!
完整Demo
最近在电商项目中用到这个效果,之前也是用NestedScrollView 实现,但是牵涉到多图时会导致页面非常的卡顿,发现使用NestedScrollView 嵌套recyclerview时 recycleview本身的复用机制就不起作用了,而是直接加载所有的item将滑动交给NestedScrollView 处理,这时图片过多就会导致界面卡顿,后来使用三方图片处理库回收,但是页面打开过多时,就导致多次触发GC,同样会卡顿,所有最后还是改为使用recyclerView 实现复杂的布局,方便同样的item的复用,所以这里更新一下使用recyclerView 实现该效果。
首先想到的是使用同样的方法实现,但是recyclerView的addOnScrollListener中给出的是相对滑动距离,实现上述效果是需要滑动的绝对距离,怎么获得绝对距离就成了关键,看代码:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
//当然前提是第一个item 存在,并且高度 > 隐藏消失所需要的滑动距离
if(manager.findFirstVisibleItemPosition() == 0){
//第一个view
View firstView = manager.findViewByPosition(0);
int height = 0 - firstView.getTop(); //第一个view距离顶部的距离
//height 就是我们想要的绝对滑动距离
//Session.getWidth() = 隐藏消失所需要的滑动距离
int baseHeight = Session.getWidth() - view1.getHeight();
//然后就是根据滑动的距离来给view设置Alpha 实现效果
view1.setAlpha((baseHeight - height) * 1.0f / baseHeight);
view2.setAlpha(1 - (baseHeight - height) * 1.0f / baseHeight);
}
}
});
关于ScrollView 和NestedScrollView 本意上二者没啥区别,就像recyclerView是listview的替代品一样,NestedScrollView 是ScrollView的替代品,Nested既是嵌套的意思,嵌套recyclerView时,只需要将recyclerview的滑动交给NestedScrollView 处理,在NestedScrollView的子布局中添加android:nestedScrollingEnabled=“false” 即可。