編輯:關於Android編程
彈性滑動也就是漸進式滑動,實現彈性滑動的方法有很多,但是他們都有一個共同的思想:將一次大的滑動分成若干次小的滑動並在一段時間內完成。本文主要介紹三種彈性滑動方式,Scroller、動畫和Handler。
本文中的“滑動”是指View內容的滑動而非View本身位置的改變。
點擊屏幕任意地方,手指與屏幕接觸時,觸發ACTION_DOWN屏幕中的文字會向上滑動400px,手指離開屏幕時觸發ACTION_UP文字下滑400px。
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int detlaX = destX - scrollX;
int scrollY = getScrollY();
int detlaY = destY - scrollY;
Log.d(TAG, "smoothScrollTo:scrollY, detlaY= " + scrollY+" " + detlaY);
mScroller.startScroll(scrollX, scrollY, detlaX, detlaY, 1000);
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
上面是使用Scroller實現彈性滑動的一個典型方法。
實現原理為:Scroller本身無法讓View彈性滑動,它需要和View的computeScroll方法配合使用才能共同完成這個功能。在startScroll()方法下調用了invalidate(),這使得View重繪,View重繪的時候會在draw方法中調用computeScroll(),在此方法中調用scrollTo滑向指定位置。之後再通過postInvalidate()進行二次重繪,如此重復直到滑動結束。
下面是computeScrollOffset()這個函數的源碼。從中可以看出判斷滑動是否結束是以timePassed為標准的。
/**
* Call this when you want to know the new location. If it returns true,
* the animation is not yet finished.
*/
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
case FLING_MODE:
...
...
break;
}
}
else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}
private static final int FRAME_COUNT = 30;
final int startX = 0;
final int deltaX = 100;
ValueAnimator animator = ValueAnimator.ofInt(0,1).setDuration(1000);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animator) {
float fraction = animator.getAnimatedFraction();
mButton1.scrollTo(startX + (int) (deltaX * fraction), 0);
}
});
animator.start();
上述代碼中,動畫本質上沒有作用於任何對象上,只是在1000ms內完成了整個動畫過程。這個方法scrollTo(startX + (int) (deltaX * fraction), 0)使得動畫每次更新時view都滑動一點。
private static final int MESSAGE_SCROLL_TO = 1;
private static final int DELAYED_TIME = 33;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_SCROLL_TO: {
mCount++;
if (mCount <= FRAME_COUNT) {
float fraction = mCount / (float) FRAME_COUNT;
int scrollX = (int) (fraction * 100);
mButton1.scrollTo(scrollX, 0);
mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO, DELAYED_TIME);
}
break;
}
default:
break;
}
};
};
在Handler的handleMessage中調用View的scrollTo方法滑動一些距離,緊接著再向Handler發送一個Delay的消息再次滑動。關鍵方法mHandler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO, DELAYED_TIME)。
示例中的動畫效果是在一個TextView進行的,滑動的是TextView中的文字。源碼如下。
/**
* Created by Spark on 2/22/2016 21:12.
*/
public class ElasticText extends TextView {
private static final String TAG = "ElasticText";
private Scroller mScroller;
private VelocityTracker mVelocityTracker;
public ElasticText(Context context) {
super(context);
init();
}
public ElasticText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ElasticText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mScroller = new Scroller(getContext());
mVelocityTracker = VelocityTracker.obtain();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
Log.d(TAG, "onTouchEvent: ActionDown");
mScroller.startScroll(getScrollX(), getScrollY(), 0, 400, 600);
invalidate();
break;
}
case MotionEvent.ACTION_MOVE: {
break;
}
case MotionEvent.ACTION_UP: {
Log.d(TAG, "onTouchEvent: ACTION_UP");
mScroller.startScroll(getScrollX(), getScrollY(), 0, -400, 600);
invalidate();
break;
}
default:
break;
}
return true;
}
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int detlaX = destX - scrollX;
int scrollY = getScrollY();
int detlaY = destY - scrollY;
mScroller.startScroll(scrollX, scrollY, detlaX, detlaY, 1000);
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
}
1、結構體的創建及導入,結構體指針等。以JniNativeInterface, DexHeader為例。解析Dex的函數如下: F5後如下:&nbs
運行結果:模擬器圖庫就三張 沒辦法~畫質挺感人~一個隱式意圖布局文件:<relativelayout xmlns:android="http://sche
Android特效專輯(十二)——仿支付寶咻一咻功能實現波紋擴散特效,精細小巧的View 先來看看這個效果 這是我的在Only上添加的效果,說實話
Android 自定義橫向滾動條。當你的橫向字段或者表格很多時候,顯示不下內容,可以使用很想滾動條進行滾動。豎向方面我添加了listview進行添加數據。兩者滾動互不干擾