編輯:關於Android編程
一直對Scroller這個類不太熟悉,之前老是在網上找著看,但是過不了多長時間後就忘記了,今天來整理一下
先看一下Scroller裡面的方法:
http://api.apkbus.com/reference/android/widget/Scroller.html
為了理解方便,拿SlideView來做說明,關於SlideView的demo網上有很多,這裡為了講解主要貼出SlideView:
public class SlideView extends LinearLayout { private Context mContext; private LinearLayout mViewContent; private LinearLayout mHolder; private TextView tv_delete; // 彈性滑動對象,實現View平滑滾動的一個幫助類 private Scroller mScroller; // 滑動回調接口,用來向上層通知滑動事件 private OnSlideListener mOnSlideListener; private int mHolderWidth = 100; private int mLastX = 0; private int mLastY = 0; private static final int TAN = 2; public SlideView(Context context) { super(context); initView(); } public SlideView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } private void initView(){ mContext = getContext(); mScroller = new Scroller(mContext); setOrientation(LinearLayout.HORIZONTAL); setGravity(Gravity.CENTER_VERTICAL); //將R.layout.slide_view 添加到this, View view=View.inflate(this,R.layout.*,null);是生成一個新的View View.inflate(mContext, R.layout.slide_view, this); mViewContent = (LinearLayout)findViewById(R.id.view_content); mHolder = (LinearLayout)findViewById(R.id.holder); tv_delete = (TextView)findViewById(R.id.delete); } public void setButtonText(CharSequence text){ tv_delete.setText(text); } public void setContentView(View view){ mViewContent.addView(view); } public void onRequireTouchEvent(MotionEvent event){ // 獲取點擊的坐標 int x = (int)event.getX(); int y = (int)event.getY(); //當前view的左上角相對於母視圖的左上角的X軸偏移量。 int scrollX = getScrollX(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: if(!mScroller.isFinished()){ mScroller.abortAnimation(); } if(mOnSlideListener != null){ mOnSlideListener.onSlide(this, OnSlideListener.SLIDE_STATUS_START_SCROLL); } break; case MotionEvent.ACTION_MOVE: //增量 int deltaX = x - mLastX; int deltaY = y - mLastY; if(Math.abs(deltaX) < Math.abs(deltaY)*TAN){ // 滑動不滿足條件 不做橫向滑動 break; } /** * 1. 這個SlideView相對於上次偏移的距離減去手指這次move的相對於上次move的增量(相對偏移量?) * * 2. 舉個例子:如果現在手指滑動,ACTION_DOWN的坐標為(100,0),現在開始MOVE滑動(ACTION_MOVE)第一個MOVE的坐標為(50,0) * * 即deltaX=50-100,第一個MOVE時scrollX = 0,newScrollX = scrollX - deltaX;newScrollX = 50 * this.scrollTo(newScrollX, 0);view是偏移50, * * 第二個MOVE的到達坐標為(10,0),而mLastX是第一個MOVE的x坐標(mLastX = 50) * deltaX=10-50 ,deltaX = -40 ;scrollX = 50 newScrollX = scrollX - deltaX;newScrollX = 90 * this.scrollTo(newScrollX, 0);view是偏移90, * */ int newScrollX = scrollX - deltaX; if(deltaX != 0){ if(newScrollX < 0){ newScrollX = 0; }else if(newScrollX > mHolderWidth){ newScrollX = mHolderWidth; } //會觸發computeScroll() this.scrollTo(newScrollX, 0); } break; case MotionEvent.ACTION_UP: int newScrollx = 0; //如果SlideView的偏移量大於默認要滑動距離的3/4,newScrollx=mHolderWidth,否則 newScrollx = 0; if(scrollX - mHolderWidth*0.75 > 0){ newScrollx = mHolderWidth; } this.smoothScrollTo(newScrollx, 0); // 通知上層滑動事件 if(mOnSlideListener != null){ mOnSlideListener.onSlide(this, newScrollx == 0 ? OnSlideListener.SLIDE_STATUS_OFF : OnSlideListener.SLIDE_STATUS_ON); } break; default: break; } mLastX = x; mLastY = y; } /** * 調用此方法滾動到目標位置 * @param fx 目標x坐標 * @param fy 目標Y坐標 */ private void smoothScrollTo(int fx, int fy){ int scrollX = getScrollX(); int dx = fx - scrollX; int scrollY = getScrollY(); int dy = fy - scrollY; //手指up之後從現在的位置偏移到scrollX+dx位置,dx是增量,觸發computeScroll mScroller.startScroll(scrollX, scrollY, dx, dy, Math.abs((dx)*3)); invalidate(); } /** * 由mScroller記錄/計算好View滾動的位置後,最後由View的computeScroll(),完成實際的滾動 */ @Override public void computeScroll() { //先判斷mScroller滾動是否完成 if(mScroller.computeScrollOffset()){ //這裡調用View的scrollTo()完成實際的滾動 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //必須調用該方法,否則不一定能看到滾動效果 postInvalidate(); } super.computeScroll(); } /** * 設置滑動回調 * @param onSlideListener */ public void setOnSlideListener(OnSlideListener onSlideListener){ this.mOnSlideListener = onSlideListener; } public interface OnSlideListener { public static final int SLIDE_STATUS_OFF = 0; public static final int SLIDE_STATUS_START_SCROLL = 1; public static final int SLIDE_STATUS_ON = 2; public void onSlide(View view, int status); } }
先說一下實現的具體思路,SlideView是一個橫向LinearLayout,作為父布局,它裡面有兩個child(當然可以更多),第一個child設置寬度充滿整個父布局,這樣的第二個child就會被擠出屏幕外面,要明確一點SlideView是無窮大的,你看到的只是屏幕顯示的那一塊,然後通過SlideView的scrollTo,讓SlideView整個平移,這樣第二個child就會顯示出來
具體講解一下:
1.ACTION_DOWN:mScroller停止動畫,這個沒什麼說的
2.ACTION_MOVE:舉個例子:SlideView已經偏移了scrollX,你下次move觸發的時候只需要偏移scrollX - deltaX就可以了,scrollTo是相對於上次偏移,getScrollX卻是向對於開始時的位置
3.ACTION_UP:在UP之前可以看到mScroller沒有做任何關於滾動的的動作,up的時候調用了
private void smoothScrollTo(int fx, int fy){
int scrollX = getScrollX();
int dx = fx - scrollX;
int scrollY = getScrollY();
int dy = fy - scrollY;
//手指up之後從現在的位置偏移到scrollX+dx位置,dx是增量,觸發computeScroll
mScroller.startScroll(scrollX, scrollY, dx, dy, Math.abs((dx)*3));
invalidate();
}
觸發了computeScroll()
@Override
public void computeScroll() {
//先判斷mScroller滾動是否完成
if(mScroller.computeScrollOffset()){
//這裡調用View的scrollTo()完成實際的滾動
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//必須調用該方法,否則不一定能看到滾動效果
postInvalidate();
}
super.computeScroll();
}
computeScroll裡面做了什麼??先mScroller.computeScrollOffset()判斷mScroller滾動是否完成,computeScrollOffset做了什麼呢?
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
float x = timePassed * mDurationReciprocal;
if (mInterpolator == null)
x = viscousFluid(x);
else
x = mInterpolator.getInterpolation(x);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
}
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
可以看出int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);mStartTime = AnimationUtils.currentAnimationTimeMillis();獲取過了多長時間,
然後if (timePassed < mDuration) ,看一下有沒有到達設置的時間,
然後一通計算mCurrX = mStartX + Math.round(x * mDeltaX);(計算是為了在mDuration時間內完成滾動dx)得到mCurrX
,然後回到computeScroll(), scrollTo(mScroller.getCurrX(), mScroller.getCurrY());在次偏移mCurrX ,
然後回調computeScroll,直到滾動結束
注意:scrollTo(),如果第一次你在x軸向左上偏移了10,下次再向左偏移10的話,相當於較之原點你已經移到了20,所以說getscrollx也是基於開始位置的偏移,現在getscrollx是20,scrollBy()是相對於你上次移動
ListView下刷新刷功能相信從事Android開發的猿友們並不陌生,包括現在Google親兒子SwipeRefreshLayout實現效果在一些APP上也能看見(不過
百學須先立志—學前須知:在我們平時加載圖片(不管是下載還是加載本地圖片…..)的時候,我們經常會遇到這樣一個需求,那就是當圖片正在加載時應該呈現
看了很多相關博客,今天也來自己梳理以下~~~Android從Linux系統啟動 init進程啟動 Native服務啟動 System Server, Android 服務
1.前言在Android安全的研究工作中,我們時常要對Android進行改進並對其進行源碼編譯,由於目前幾乎所有的手機廠商均對其底層驅動實行封閉政策,導致我們在完成And