個人思路:
說到齊劉海適配,最典型的就是MainActivity的幾個fragment中有的需要透明系統狀態欄 有的不需要, 而一般需要透明系統狀態欄的fragment頂部都會放個輪播圖,然後在輪播圖上放搜索框,所謂適配,就是指搜索框的位置根據系統狀態欄高度設置,達到在齊劉海手機上搜索框不被覆蓋;
如上圖所示,下面對如動態圖所示系統狀態欄進行三步分析
一、獲取系統狀態欄高度
兩行代碼就能獲取當前系統狀態欄的高度
int resourceId = mContext.getResources().getIdentifier("status_bar_height", "dimen", "android");
int viewHeight = mContext.getResources().getDimensionPixelSize(resourceId);
二、設置顏色
根據UI的需求,我的做法是先設置系統狀態欄透明,監聽手勢動作,開始滑動時,增加一個系統狀態欄同高的view,更改背景色漸變(漸變值爲0-100%,百分比同 滑動距離/輪播圖高度),更改系統狀態欄圖標顏色爲深色,再重寫scrollview,監聽滑動置頂時,設置透明系統狀態欄,隱藏佔位view;
/**
* 設置透明系統狀態欄
*/
View decorView = getActivity().getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
getActivity().getWindow().setStatusBarColor(Color.parseColor("#00000000"));//設置透明
/**
* 設置系統狀態欄圖標顏色,用false和true 設置顏色爲白色或者深色
*/
StatusBarCompat.setLightStatusBar(getActivity().getWindow(), false);
/**
* 滑動監聽
*/
private MyScrollView.OnMyScrollListener listener;
listener = new MyScrollView.OnMyScrollListener() {
@Override
public void onScrollStateChanged(MyScrollView view, int state) {
String str;
if (state == 0) {
str = "IDLE";
} else if (state == 1) {
str = "DRAG";
} else if (state == 2) {
str = "FLING";
} else {
str = "ERROR";
}
Log.d("brycegao", "滑動狀態:" + str);
}
@Override
public void onScroll(MyScrollView view, int y) {
int height = banner.getHeight();
if (scroll_view.getScrollY() > 0) {
if (scroll_view.getScrollY() < height) {
float scale = (float) scroll_view.getScrollY() / height;
float alpha = (255 * scale);
//百分比漸變
view_placeholder.setBackgroundColor(Color.argb((int) alpha, 0xff, 0xff, 0xff));
//獲取系統狀態欄高度
int resourceId = mContext.getResources().getIdentifier("status_bar_height", "dimen", "android");
//獲取屏幕寬度
int viewWidth = (int) (ScreenUtils.getScreenWidth(mContext));
if (resourceId > 0) {
int viewHeight = mContext.getResources().getDimensionPixelSize(resourceId);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(viewWidth, viewHeight);
view_placeholder.setLayoutParams(params);
}
StatusBarCompat.setLightStatusBar(getActivity().getWindow(), true);//設置導航欄字體顏色
}
}
}
@Override
public void onScrollToTop() {
Log.d("brycegao", "滑到頂部");
view_placeholder.setLayoutParams(new RelativeLayout.LayoutParams(0, 0));
StatusBarCompat.setLightStatusBar(getActivity().getWindow(), false);//設置導航欄字體顏色
}
@Override
public void onScrollToBottom() {
Log.d("brycegao", "滑動底部");
}
};
/**
* 自定義scrollview 監聽滑動事件,網上找的,親測可用,不過原文地址忘了 勿怪、見諒
*/
public class MyScrollView extends ScrollView {
private ArrayList<OnMyScrollListener> listeners;
private int currentState;
private boolean isLastBottom; //上次刷新是否底部
private int lastDrawPos; //上次刷新的縱向位移
public interface OnMyScrollListener {
int SCROLL_STATE_FLING = 2; //手指滑動後鬆開,自動滑動
int SCROLL_STATE_IDLE = 0; //不滑動
int SCROLL_STATE_TOUCH_SCROLL = 1; //手指按着屏幕滑動
void onScrollStateChanged(MyScrollView view, int state);
void onScroll(MyScrollView view, int y); //滑動距離
void onScrollToTop(); //滑到頂部
void onScrollToBottom(); //滑到底部
}
public MyScrollView(Context context) {
super(context);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
listeners = new ArrayList<>();
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override public boolean onTouchEvent(MotionEvent ev) {
boolean lastDragState = getDragState();
boolean ret = super.onTouchEvent(ev);
if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
for (OnMyScrollListener listener:listeners) {
listener.onScroll(this, getScrollY());
}
}
if ((ev.getActionMasked() == MotionEvent.ACTION_UP
|| ev.getActionMasked() == MotionEvent.ACTION_CANCEL)
&& currentState == OnMyScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
//取消滑動
currentState = OnMyScrollListener.SCROLL_STATE_IDLE;
for (OnMyScrollListener listener:listeners) {
listener.onScrollStateChanged(this, OnMyScrollListener.SCROLL_STATE_IDLE);
}
}
boolean curDragState = getDragState();
//拖動
if (!lastDragState && curDragState) {
currentState = OnMyScrollListener.SCROLL_STATE_TOUCH_SCROLL;
for (OnMyScrollListener listener:listeners) {
listener.onScrollStateChanged(this, OnMyScrollListener.SCROLL_STATE_TOUCH_SCROLL);
}
}
return ret;
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (lastDrawPos == getScrollY()
&& getScrollY() > 0
&& currentState == OnMyScrollListener.SCROLL_STATE_FLING ) {
currentState = OnMyScrollListener.SCROLL_STATE_IDLE; //設置狀態爲空閒
for (OnMyScrollListener listener:listeners) {
listener.onScrollStateChanged(this, OnMyScrollListener.SCROLL_STATE_IDLE);
}
}
if (getScrollY() == 0 && lastDrawPos == 0
&& currentState != OnMyScrollListener.SCROLL_STATE_IDLE) {
currentState = OnMyScrollListener.SCROLL_STATE_IDLE; //設置狀態爲空閒
for (OnMyScrollListener listener:listeners) {
listener.onScrollStateChanged(this, OnMyScrollListener.SCROLL_STATE_IDLE);
listener.onScrollToTop();
}
}
lastDrawPos = getScrollY();
if (isCurrentBottom()
&& !isLastBottom) {
for (OnMyScrollListener listener:listeners) {
listener.onScrollToBottom();
}
}
isLastBottom = isCurrentBottom();
}
@Override public void fling(int velocityY) {
super.fling(velocityY);
if (getChildCount() > 0) {
currentState = OnMyScrollListener.SCROLL_STATE_FLING;
for (OnMyScrollListener listener:listeners) {
listener.onScrollStateChanged(this, OnMyScrollListener.SCROLL_STATE_FLING);
}
}
}
//判斷是否滑到底部
private boolean isCurrentBottom() {
boolean ret = false;
int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
int heightPadding; //scrollview上下padding之和
View child = getChildAt(0);
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (targetSdkVersion >= Build.VERSION_CODES.M) {
heightPadding = getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin;
} else {
heightPadding = getPaddingTop() + getPaddingBottom();
}
if (getMeasuredHeight() - heightPadding + getScrollY() == child.getMeasuredHeight()) {
ret = true;
}
return ret;
}
//反射查詢mIsBeingDragged
private boolean getDragState() {
boolean state = false;
try {
Class clz = ScrollView.class;
Field field = clz.getDeclaredField("mIsBeingDragged");
field.setAccessible(true);
state = field.getBoolean(this);
} catch (Exception ex) {
ex.printStackTrace();
}
return state;
}
//滑動加速器是否停止
private boolean isfinishScroll() {
boolean isfinish=false;
Class scrollview=ScrollView.class;
try {
Field scrollField=scrollview.getDeclaredField("mScroller");
scrollField.setAccessible(true);
Object scroller=scrollField.get(this);
Class overscroller= scrollField.getType();
Method finishField=overscroller.getMethod("isFinished");
finishField.setAccessible(true);
isfinish= (boolean) finishField.invoke(scroller);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return isfinish;
}
/**
* 添加滑動監聽
* @param listener
*/
public void addOnScrollListner(OnMyScrollListener listener) {
if (listener == null) {
throw new IllegalArgumentException("invalid listener");
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeOnScrollListener(OnMyScrollListener listener) {
if (listener == null) {
throw new IllegalArgumentException("invalid listener");
}
listeners.remove(listener);
}
}
三、UI適配
其實這個UI適配也很簡單的,就是設置搜索框的paddingTop爲系統狀態欄的高度+xdp,這裏就不寫代碼了