編輯:關於Android編程
CoordinatorLayout協同布局在一般只結合RecyclerView和NestedScrollView使用,如果我使用ListView沒有效果的。但是,由於業務原因使用ListView,有需要實現協同的效果怎麼辦?
其實分析RecyclerView和NestedScrollView的源碼可以知道,他們都實現了一個接口NestedScrollingChild,所以我們可以自定義ListView,實現NestedScrollingChild接口就好。當然除此外,google還提供了一個API
mListView.setNestedScrollingEnabled(true),就可以使用。當然,這2種方法只有在Android5.0以上才有效果。
下面就滑動ListView,讓fab懸浮按鈕滑動出現和滑動消失為例:
這裡需要自定義一個Behavior類,這個類將作用於fab懸浮按鈕,也就是在fab懸浮按鈕中使用這個屬性,如下:
app:layout_behavior="www.weshared.listviewandcoor.QuickReturnFooterBehavior"
具體代碼如下:
activity_main.xml
<android.support.design.widget.coordinatorlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitssystemwindows="true" tools:context="www.weshared.listviewandcoor.MainActivity"> <android.support.design.widget.appbarlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popuptheme="@style/AppTheme.PopupOverlay"> </android.support.v7.widget.toolbar></android.support.design.widget.appbarlayout> <include layout="@layout/content_main"> <android.support.design.widget.floatingactionbutton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" app:layout_behavior="www.weshared.listviewandcoor.QuickReturnFooterBehavior" android:layout_margin="@dimen/fab_margin" android:src="@android:drawable/ic_dialog_email"> </android.support.design.widget.floatingactionbutton></include></android.support.design.widget.coordinatorlayout></code>
content_main.xml
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="www.weshared.listviewandcoor.MainActivity" tools:showin="@layout/activity_main"> <listview android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="wrap_content"> </listview></relativelayout></code>
list_item.xml
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="60dp"> <textview xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv_item" android:layout_width="match_parent" android:layout_height="60dp" android:gravity="center" android:text="ee"> </textview> </relativelayout></code>
MainActivity文件中
public class MainActivity extends AppCompatActivity {
private ArrayList mdatas = new ArrayList();
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initView();
}
private void initView() {
mListView = (ListView) findViewById(R.id.lv);
//API21以上才有效果----第二種方式,比較簡便
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mListView.setNestedScrollingEnabled(true);
}
initData();
mListView.setAdapter(new MyListAdapter(mdatas));
}
private void initData() {
for(int i=0;i<30;i++){
mdatas.add("---------"+i+"-----------");
}
}
}
MyListAdapter文件就省略吧
自定義ListView實現NestedScrollingChild接口,看代碼也可以知道,其實發揮作用的就是setNestedScrollingEnabled(true)這個方法
public class NestedScrollingListView extends ListView implements NestedScrollingChild {
private NestedScrollingChildHelper mNestedScrollingChildHelper;
public NestedScrollingListView(final Context context) {
super(context);
initHelper();
}
public NestedScrollingListView(final Context context, final AttributeSet attrs) {
super(context, attrs);
initHelper();
}
public NestedScrollingListView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
initHelper();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public NestedScrollingListView(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initHelper();
}
private void initHelper() {
mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
@Override
public void setNestedScrollingEnabled(final boolean enabled) {
mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean isNestedScrollingEnabled() {
return mNestedScrollingChildHelper.isNestedScrollingEnabled();
}
@Override
public boolean startNestedScroll(final int axes) {
return mNestedScrollingChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mNestedScrollingChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mNestedScrollingChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(final int dxConsumed, final int dyConsumed, final int dxUnconsumed, final int dyUnconsumed, final int[] offsetInWindow) {
return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(final int dx, final int dy, final int[] consumed, final int[] offsetInWindow) {
return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(final float velocityX, final float velocityY, final boolean consumed) {
return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(final float velocityX, final float velocityY) {
return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
}
最重要的一個類Behavior的實現類
public class QuickReturnFooterBehavior extends CoordinatorLayout.Behavior {
private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
private int mDySinceDirectionChange;
private boolean mIsShowing;
private boolean mIsHiding;
public QuickReturnFooterBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dx, int dy, int[] consumed) {
if (dy > 0 && mDySinceDirectionChange < 0
|| dy < 0 && mDySinceDirectionChange > 0) {
// We detected a direction change- cancel existing animations and reset our cumulative delta Y
child.animate().cancel();
mDySinceDirectionChange = 0;
}
mDySinceDirectionChange += dy;
if (mDySinceDirectionChange > child.getHeight()
&& child.getVisibility() == View.VISIBLE
&& !mIsHiding) {
hide(child);
} else if (mDySinceDirectionChange < 0
&& child.getVisibility() == View.GONE
&& !mIsShowing) {
show(child);
}
}
/**
* Hide the quick return view.
*
* Animates hiding the view, with the view sliding down and out of the screen.
* After the view has disappeared, its visibility will change to GONE.
*
* @param view The quick return view
*/
private void hide(final View view) {
mIsHiding = true;
ViewPropertyAnimator animator = view.animate()
.translationY(view.getHeight())
.setInterpolator(INTERPOLATOR)
.setDuration(200);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {}
@Override
public void onAnimationEnd(Animator animator) {
// Prevent drawing the View after it is gone
mIsHiding = false;
view.setVisibility(View.GONE);
}
@Override
public void onAnimationCancel(Animator animator) {
// Canceling a hide should show the view
mIsHiding = false;
if (!mIsShowing) {
show(view);
}
}
@Override
public void onAnimationRepeat(Animator animator) {}
});
animator.start();
}
/**
* Show the quick return view.
*
* Animates showing the view, with the view sliding up from the bottom of the screen.
* After the view has reappeared, its visibility will change to VISIBLE.
*
* @param view The quick return view
*/
private void show(final View view) {
mIsShowing = true;
ViewPropertyAnimator animator = view.animate()
.translationY(0)
.setInterpolator(INTERPOLATOR)
.setDuration(200);
animator.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
view.setVisibility(View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animator) {
mIsShowing = false;
}
@Override
public void onAnimationCancel(Animator animator) {
// Canceling a show should hide the view
mIsShowing = false;
if (!mIsHiding) {
hide(view);
}
}
@Override
public void onAnimationRepeat(Animator animator) {}
});
animator.start();
}
}
參考原文Android PopupWindow用法解析進行學習,通過實例及PopupWindow源碼分析了PopupWindow的使用。文章最後的“補充Case: 彈窗不
前言雅虎天氣的界面上滑的時候背景圖片會跟著移動,最重要的是背景圖片會根據手指上下移動的距離來進行不同程度的模糊,感覺甚為驚奇,畢竟大家都知道,在Android平台上進行模
Android 平台提供了兩類動畫。 一類是Tween動畫,就是對場景裡的對象不斷的進行圖像變化來產生動畫效果(旋轉、平移、放縮和漸變)。 下面就講一下Tweene An
對於很多新手來說,自己搭建一個開發環境的確不是一件容易的事;對於“老手”的開發者,搭建開發環境同樣也是一件麻煩的事,畢竟耗時費勁。但是,如果把相關