先说一下要实现的效果:
1、利用ScrollView来实现可以拖动的动态布局
2、动态添加View来组成视图
3、没有长按时ScrollView有fading的效果(向上隐藏ActionBar,向下展开ActionBar)
4、长按时ScrollView不滑动,被长按的图标跟着手指移动
首先说一下第三点的实现:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/fab__header_container" />
<com.manuelpeinado.fadingactionbar.view.ObservableScrollView
android:id="@+id/fab__scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none">
<LinearLayout
android:id="@+id/fab__container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/fab__content_top_margin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent" />
</LinearLayout>
</com.manuelpeinado.fadingactionbar.view.ObservableScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:gravity="center"
android:id="@+id/action">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title" />
</LinearLayout>
</FrameLayout>
注解:header_container就是头部的布局这里我是用一个ImageView来表示,然后就是ObservableScrollView(重写ScrollView将其OnScrollChange接口暴露出来)里面包含一个fab__content_top_margin(透明的布局,其高度是根据scroll改变的,为了有向上(向下)移动的感觉),ObservableScrollView的主要View是在代码中动态添加的!
下面是header滑动的控制(会比top_margin慢):
private void addParallaxEffect(int scrollPosition) {
int dampedScroll = (int) (scrollPosition * 0.5);
int offset = mLastDampedScroll - dampedScroll;
mHeaderContainer.offsetTopAndBottom(offset);
if (mFirstGlobalLayoutPerformed) {
mLastDampedScroll = dampedScroll;
}
}
注解:mFirstGlobalLayoutPerformed是判断整个布局树是否布局完成,offsetTopAndBottom(offset)控制headerView上下移动
top_margin的移动:
private void updateHeaderHeight(int headerHeight) {
ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) mMarginView.getLayoutParams();
params.height = headerHeight;
mMarginView.setLayoutParams(params);
mLastHeaderHeight = headerHeight;
}
监听OnsrollView的滑动监听:
private void onNewScroll(int scrollPosition) {
int currentHeaderHeight = mHeaderContainer.getHeight();
Log.e("currentHeaderHeight", "" + currentHeaderHeight);
if (currentHeaderHeight != mLastHeaderHeight) {
updateHeaderHeight(currentHeaderHeight);
}
int headerHeight = currentHeaderHeight - getActionBarHeight();
float ratio = (float) Math.min(Math.max(scrollPosition, 0), headerHeight) / headerHeight;
int newAlpha = (int) (ratio * 255);
mActionBarBackgroundDrawable.setAlpha(newAlpha);
addParallaxEffect(scrollPosition);
}
长按之后拖动图标(解决与ScrollChange的冲突):
1、模拟长按效果:
private Runnable MyTimer = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
isCanMove = true;
Log.e("isCanMove", "" + "" + isCanMove);
mVibrator.vibrate(50); //震动一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
注解:如果长按事件不到1000mm就触发UP事件,那么MyTimer就会捕捉到InterruptedException,然后就不会执行isCanMove = true;
在ScrollView重写DispatchTouchEvent
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean isScroll = true;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.e("dispatchTouchEvent", "" + "ACTION_DOWN");
timer = new Thread(MyTimer);
timer.start();
break;
case MotionEvent.ACTION_UP:
Log.e("dispatchTouchEvent", "" + "ACTION_UP");
if (timer != null && !isCanMove) {
timer.interrupt();
} else {
isCanMove = false;
}
break;
case MotionEvent.ACTION_MOVE:
if (isCanMove) {
isScroll = false;
Log.e("dispatchTouchEvent", "" + "ACTION_MOVE");
}
break;
}
if (isScroll) {
return super.dispatchTouchEvent(ev);
} else {
return true;
}
}
注解:在长按之后我希望ScrollView不可滑动,所以我设置一个标志值isScroll来判断其是否可以滑动,return true说明ScrollView不可滑动