編輯:關於Android編程
本文主要講述Launcher3屏幕滑動過程,首先需要了解Android的觸摸事件分發機制。關於分發機制,可查看文章Android事件分發機制。
PagedView是滑屏最主要的類,下面是init()方法出初始化參數,假設以1080*1440分辨率,即densiy=3為例,來計算各個阈值。
protected void init() {
mDirtyPageContent = new ArrayList<Boolean>();
mDirtyPageContent.ensureCapacity(32);
mScroller = new LauncherScroller(getContext()); //初始化滾動器LauncherScroller
setDefaultInterpolator(new ScrollInterpolator()); //設置插值器為ScrollInterpolator
mCurrentPage = 0;
mCenterPagesVertically = true;
// 獲取ViewConfiguration
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
//mTouchSlop = 16dp;
mTouchSlop = configuration.getScaledPagingTouchSlop();
//mPagingTouchSlop = 16dp;
mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
//最大速度8000dp/s;
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
//獲取屏幕密度系數mDensity
mDensity = getResources().getDisplayMetrics().density;
//用於刪除的拋出阈值: -1440*3
mFlingToDeleteThresholdVelocity =
(int) (mFlingToDeleteThresholdVelocity * mDensity);
//滾動速度阈值 500 *3 px/s
mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
//最小滾動速度值 250 *3 px/s
mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity);
//最小snap速度值1500 *3 px/s
mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity);
setOnHierarchyChangeListener(this);
}
下面主要講述:Workspace,PagedView 這兩個關於滑屏最為核心的類,也是代碼量最大的類。
先來看看launcher桌面的整體UI布局圖:
當手指按下時,觸發ACTION_DOWN事件,由Activity
當手指按下時,還沒有准備滾動,此時mTouchState = TOUCH_STATE_REST
,故Worksapce,PagedView並不會攔截事件,雖然沒有攔截器進行攔截,也沒有onTouchEvent消費,但由於CellLayout的clickable=”true”,故ACTION_DOWN事件仍然是被消費了,具體說明見上一篇文章Android事件分發機制.
決定是否屏幕是否開始滑動的阈值計算:
mTouchSlop = configuration.getScaledPagingTouchSlop()當手指移動距離>mTouchSlop時,Wokespace開始攔截ACTION_MOVE事件,並調用scrollBy()
,這是整個過程第一次屏幕移動。每收到一次ACTION_MOVE事件,並執行scrollBy()
事件,直到用戶手指離開屏幕。並執行scrollBy()
事件,最終調用的還是View.scrollTo()
來進行屏幕的滾動操作。
達到下面兩種情況之一,都可以觸發launcher滑屏事件:
滑動距離超過屏幕寬度的0.4倍,SIGNIFICANT_MOVE_THRESHOLD = 0.4 boolean isSignificantMove = Math.abs(deltaX) > pageWidth * SIGNIFICANT_MOVE_THRESHOLD;
速度 大於500dp/s, 且滑動距離大於 25px。 boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING && Math.abs(velocityX) > mFlingThresholdVelocity;
當滿足屏幕翻頁的條件時,開始執行翻頁動畫,通過插值器ScrollInterpolator
來計算每一步需要移動的距離。 插值函數為:f(t)=1+(t-1)^5
。不斷循環,直到timePassed > mDuration時,動畫結束。
用於判斷是否進行滑動操作
protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
// Disallow scrolling if we don't have a valid pointer index
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) return;
// Disallow scrolling if we started the gesture from outside the viewport
final float x = ev.getX(pointerIndex);
final float y = ev.getY(pointerIndex);
if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return;
final int xDiff = (int) Math.abs(x - mLastMotionX);
final int yDiff = (int) Math.abs(y - mLastMotionY);
final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
boolean xPaged = xDiff > mPagingTouchSlop;
boolean xMoved = xDiff > touchSlop;
boolean yMoved = yDiff > touchSlop;
//當滑動距離足夠時,才開始滑動
if (xMoved || xPaged || yMoved) {
if (mUsePagingTouchSlop ? xPaged : xMoved) {
// Scroll if the user moved far enough along the X axis
mTouchState = TOUCH_STATE_SCROLLING;
mTotalMotionX += Math.abs(mLastMotionX - x);
mLastMotionX = x;
mLastMotionXRemainder = 0;
mTouchX = getViewportOffsetX() + getScrollX();
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
onScrollInteractionBegin();
pageBeginMoving();
}
}
}
手指離開屏幕後,調用的滑動動畫的方法
protected void snapToPage(int whichPage, int delta, int duration, boolean immediate,
TimeInterpolator interpolator) {
whichPage = validateNewPage(whichPage);
mNextPage = whichPage;
View focusedChild = getFocusedChild();
if (focusedChild != null && whichPage != mCurrentPage &&
focusedChild == getPageAt(mCurrentPage)) {
focusedChild.clearFocus();
}
sendScrollAccessibilityEvent();
pageBeginMoving();
awakenScrollBars(duration);
if (immediate) {
duration = 0;
} else if (duration == 0) {
duration = Math.abs(delta);
}
if (!mScroller.isFinished()) {
abortScrollerAnimation(false);
}
if (interpolator != null) {
mScroller.setInterpolator(interpolator);
} else {
// 插值器為ScrollInterpolator
mScroller.setInterpolator(mDefaultInterpolator);
}
//這個整個滑動的開始點
mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
updatePageIndicator();
// Trigger a compute() to finish switching pages if necessary
if (immediate) {
computeScroll();
}
// Defer loading associated pages until the scroll settles
mDeferLoadAssociatedPagesUntilScrollCompletes = true;
mForceScreenScrolled = true;
invalidate();
}
滑屏時的插值器
private static class ScrollInterpolator implements Interpolator {
public ScrollInterpolator() {
}
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t * t * t + 1;
}
}
launcher桌面的滑動器 mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
//計算 pixels/(s^2)
private float computeDeceleration(float friction) {
return SensorManager.GRAVITY_EARTH // g (m/s^2)
* 39.37f // inch/meter
* mPpi // pixels per inch
* friction;
}
//獲取速度
public float getCurrVelocity() {
return mMode == FLING_MODE ?
mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f;
}
computeScroll():重寫了父類的computeScroll();主要功能是計算拖動的位移量、更新背景、設置要顯示的屏幕
怎麼在安卓模擬器裡面安裝app?它不像別的軟件那樣一拉一拖就進去的,我開始也是這樣的,老是安裝不了,後來讓我嘗試了,我才知道。下面是我跟大家一起分享一下怎麼
1.利用SimpleAdapter適配器實現。 這裡以每一個網格中添加一張圖片和相應的文字說明為例: main.xml 因為除了添加圖片
很久沒用開源項目,重新復習一下下拉刷新 也是想總結下一個項目,應該需要那些東西, 為自己打下基礎, 你也可以自己去下 library,關於源碼我會在後面放在 效果圖 p
1.自定義控件時鐘的布局和Java類values文件下的attrs.xml <!--?xml version="1.0" encoding=&q