編輯:關於Android編程
先從最簡單的看起
效果如下所示,toolbar可以伸展
AppBarLayout裡有個接口,叫做OnOffsetChangedListener,如果AppBarLayout滑動了就會觸發裡面的回調onOffsetChanged
/** * Interface definition for a callback to be invoked when an {@link AppBarLayout}'s vertical * offset changes. */ public interface OnOffsetChangedListener { /** * Called when the {@link AppBarLayout}'s layout offset has been changed. This allows * child views to implement custom behavior based on the offset (for instance pinning a * view at a certain y value). * * @param appBarLayout the {@link AppBarLayout} which offset has changed * @param verticalOffset the vertical offset for the parent {@link AppBarLayout}, in px */ void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset); }
AppBarLayout滑動的時候會調用setHeaderTopBottomOffset,裡面調用dispatchOffsetUpdates(appBarLayout),如下所示,會把移動的消息發給listeners
private void dispatchOffsetUpdates(AppBarLayout layout) { final Listlisteners = layout.mListeners; // Iterate backwards through the list so that most recently added listeners // get the first chance to decide for (int i = 0, z = listeners.size(); i < z; i++) { final OnOffsetChangedListener listener = listeners.get(i); if (listener != null) { listener.onOffsetChanged(layout, getTopAndBottomOffset()); } } }
而CollapsingToolbarLayout在onAttachedToWindow的時候加入
((AppBarLayout) parent).addOnOffsetChangedListener(mOnOffsetChangedListener);
其實就是注冊了一個listener,AppBarLayout滑動了,CollapsingToolbarLayout 內的mOnOffsetChangedListener就會知道並作出相應動畫,這裡其實就是文字的縮小。主要代碼在CollapsingTextHelper內,主要就是根據當前AppBarLayout的offset來修改mScale。
此時CollapsingToolbarLayout和AppBarLayout一樣大小,包含statusbar 大小為256dp
mTotalScrollRange=range - getTopInset()=256dp-S=609
mDownPreScrollRange 0
mDownScrollRange =256dp=672
我曾經以為mTotalScrollRange= mDownPreScrollRange+ mDownScrollRange,這裡不成立了。
我試著把mDownScrollRange強行改為609,滑動依然正常,因為下滑的時候offset是在變大的,所以不會到-672.
再看設置了exitUntilCollapsed 之後,exitUntilCollapsed意思就是滑出直到折疊狀態,即滑出的時候最多到折疊狀態,無法完全滑出
exitUntilCollapsed會改變上滑的范圍,上滑的范圍就是mTotalScrollRange,
private int getUpNestedPreScrollRange() { return getTotalScrollRange(); }
public final int getTotalScrollRange() { if (mTotalScrollRange != INVALID_SCROLL_RANGE) { return mTotalScrollRange; } int range = 0; for (int i = 0, z = getChildCount(); i < z; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int childHeight = child.getMeasuredHeight(); final int flags = lp.mScrollFlags; if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) { // We're set to scroll so add the child's height range += childHeight + lp.topMargin + lp.bottomMargin; if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) { // For a collapsing scroll, we to take the collapsed height into account. // We also break straight away since later views can't scroll beneath // us //減去標記了SCROLL_FLAG_EXIT_UNTIL_COLLAPSED的child的最小高度 range -= ViewCompat.getMinimumHeight(child); break; } } else { // As soon as a view doesn't have the scroll flag, we end the range calculation. // This is because views below can not scroll under a fixed view. break; } } return mTotalScrollRange = Math.max(0, range - getTopInset()); }
由上可知,在算mTotalScrollRange的時候會減去標記了SCROLL_FLAG_EXIT_UNTIL_COLLAPSED的child的最小高度,這裡就是減去CollapsingToolbarLayout的minHeight,但是又有個問題,CollapsingToolbarLayout我們並沒有設置minHeight,我們只是在Toolbar裡設置了minHeight。CollapsingToolbarLayout在onLayout的時候會調用setMinimumHeight(getHeightWithMargins(mToolbar));,這樣CollapsingToolbarLayout就有了minHeight,這個值是toolbar的height加上下margin,跟Toolbar的minHeight沒關系。試試看把Toolbar的minHeight去掉,毫不影響。所以此時mTotalScrollRange會減去CollapsingToolbarLayout的minHeight,這樣上滑的時候就會留出一部分高度,不全部滑出,留出的高度就是CollapsingToolbarLayout的minHeight=toolbar高度+上下margin
Toolbar設置app:layout_collapseMode=”pin”
這居然可以定住toolbar,和appbarlayout的設計又有點不符合,appbarlayout是認為底部可以存在不滑動的區域,但頂部不可以,那這裡怎麼做到的,實際上,他是隨著appbarlayout往上offset了,然後他自己之後又offset了一次,使得toolbar相對屏幕的位置不變。實際上,假設appbarlayout往上滑了11,那麼appbarlayout的offset是-11,此時我們又offset了一次,把toolbar相對CollapsingToolbarLayout的offset設置為11,這樣toolbar相對屏幕就相當於沒變化,核心代碼在android.support.design.widget.CollapsingToolbarLayout.OffsetUpdateListener#onOffsetChanged<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;"> //CollapsingToolbarLayout.OffsetUpdateListener#onOffsetChanged for (int i = 0, z = getChildCount(); i < z; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final ViewOffsetHelper offsetHelper = getViewOffsetHelper(child); switch (lp.mCollapseMode) { case LayoutParams.COLLAPSE_MODE_PIN: //調整offset使得child看起來不動 if (getHeight() - insetTop + verticalOffset >= child.getHeight()) { offsetHelper.setTopAndBottomOffset(-verticalOffset); } break; case LayoutParams.COLLAPSE_MODE_PARALLAX: //調整offset實現視差滑動 offsetHelper.setTopAndBottomOffset( Math.round(-verticalOffset * lp.mParallaxMult)); break; } }
上滑的過程中,背景由圖片變成純色,狀態欄也由透明變為純色,這個變化是什麼時候呢?這個臨界點由getScrimTriggerOffset決定
//CollapsingToolbarLayout.OffsetUpdateListener#onOffsetChanged // Show or hide the scrims if needed if (mContentScrim != null || mStatusBarScrim != null) { setScrimsShown(getHeight() + verticalOffset < getScrimTriggerOffset() + insetTop); } /** * The additional offset used to define when to trigger the scrim visibility change. */ final int getScrimTriggerOffset() { return 2 * ViewCompat.getMinimumHeight(this); }
截了個圖,大概是這個位置,圖片可見部分的高度就是getScrimTriggerOffset的值,下一瞬間圖片就會變成純色。實際上就是在上面蓋了個mContentScrim,mContentScrim就是一個ColorDrawable ,顏色為colorPrimary.由此可見修改CollapsingToolbarLayout的minHeight就可以修改變化瞬間的位置
變成純色的同時,狀態欄也從透明變為有顏色colorPrimaryDark。mScrimAlpha由1變為255,狀態欄變為純色,實際上是在狀態欄的位置畫了一個純色的矩形,由mStatusBarScrim來實現,mStatusBarScrim的顏色也可以指定。
if (mStatusBarScrim != null && mScrimAlpha > 0) { final int topInset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0; if (topInset > 0) { mStatusBarScrim.setBounds(0, -mCurrentOffset, getWidth(), topInset - mCurrentOffset); mStatusBarScrim.mutate().setAlpha(mScrimAlpha); mStatusBarScrim.draw(canvas); } }
對應case3
給ImageView加上fitSystemWindow,為什麼就有效果,讓初始態覆蓋狀態欄
不加的話,ImageView會被設置一個offset(insetTop),讓他處於狀態欄下邊,如果加了,那就進不到L7,所以可以覆蓋狀態欄。
//android.support.design.widget.CollapsingToolbarLayout#onLayout if (mLastInsets != null && !ViewCompat.getFitsSystemWindows(child)) { final int insetTop = mLastInsets.getSystemWindowInsetTop(); if (child.getTop() < insetTop) { // If the child isn't set to fit system windows but is drawing within the inset // offset it down ViewCompat.offsetTopAndBottom(child, insetTop); } }
再來看看enterAlwaysCollapsed有什麼用
我拿CollapsImageActivity3試了一下,app:layout_scrollFlags=”scroll|enterAlways|enterAlwaysCollapsed” 發現有bug,下滑pre的時候顯示如下,應該是下滑的范圍(mDownPreScrollRange)少算了個statubar。暫時沒有什麼好的解決方案,看google後期會不會修復這個bug還是放棄enterAlwaysCollapsed。
SQLite 是一款輕量級的關系型數據庫Android為了讓我們能夠更加方便地管理數據庫,專門提供了一個SQLiteOpenHelper幫助類,借助這個類就可以非常簡單地
今天在修改一個布局問題時候,發現自己對權重的理解還不夠。首先問題如圖:一個TextView沒有按要求顯示完整,顯示成了2行。怎麼辦呢?方法1:是把它左面的字體放小。結果師
效果 (關於gif怎麼生成的,我先錄手機的屏幕得到mp4文件,然後用這個網址:https://cloudconvert.com/mp4-to-gif 進行的mp4轉
/***@author StormMaybin*@Date 2016-09-1*/ 生命不息,奮斗不止!WebView 對於,WebView 顧名思義,就是顯示各種各樣的