實例演示自定義View和Scroller的使用

在之前的文章中句携,已經(jīng)介紹過View的坐標系,滑動等相關(guān)內(nèi)容允乐。今天結(jié)合一個具體的例子來演示一下务甥。
首先介紹一下Scroller。

Scroller

Scroller是一個滑動的輔助類喳篇,它主要包含以下內(nèi)容

  1. startScroll(int startX, int startY, int dx, int dy, int duration)
    startX: 滑動開始的X位置
    dx: 將要滑動的距離
    duration:在多長時間內(nèi)完成滑動

  2. getScrollX(),getScrollY()
    獲取滑動距離

需要注意的是敞临,在Scroll相關(guān)的方法中,包括scrollTo麸澜,scrollBy挺尿,getScrollX(),startScroll炊邦,他們的參數(shù)是有方向的编矾,與View的坐標系不同,向右馁害,向下為負值窄俏,反之為正值。

舉個例子:
首先通過scrollTo(100,50)將View的內(nèi)容滑動碘菜,View的位置會向左凹蜈,上移動 100,50 個像素。此時忍啸,通過getScrollX/Y()獲取到的值仰坦,就是 100 , 50

然后通過scrollBy(-20, -10)再移動一下View计雌,此時View會向右悄晃,下移動 20,10 個像素,然后通過getScrollX/Y()獲取到的值為100-20=80,50-10=40凿滤,View的內(nèi)容位于初始位置的左上方妈橄。

簡單的總結(jié)一下:

getScrollX/Y()得到的是當(dāng)前View的內(nèi)容與View的初始位置之間的距離,右下為負翁脆,反之為正眷蚓。
startScroll(int startX, int startY, int dx, int dy, int duration):
startX/Y表示滑動開始的位置(通常由getScrollX/Y()得到)
dX/Y表示將要滑動的距離,右下為負鹃祖,反之為正溪椎。
稍后會在具體的例子中演示。

  1. invalidate();
    invalidate();是View中的方法恬口,會調(diào)用draw校读,進行View重繪,跟在startScroll方法之后祖能。startScroll實際上只是告訴View怎樣滑動歉秫,invalidate()之后才會開始滑動。

  2. 重寫computeScroll()
    這個方法才是實現(xiàn)彈性滑動的關(guān)鍵养铸。彈性滑動雁芙,可以理解為平滑的移動,我們通過scrollTo/By钞螟,實現(xiàn)的滑動是一下就完成的兔甘,彈性滑動是緩慢平滑的移動。computeScroll()是怎樣實現(xiàn)彈性滑動的呢鳞滨?
    看一下代碼就明白了:

    @Override
    public void computeScroll() {
        if(mScroller.computeScrollOffset()){
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

computeScroll是在draw方法中調(diào)用的洞焙,startScroll之后的invalidate會調(diào)用draw方法,draw又調(diào)用了computeScroll拯啦,if里的條件mScroller.computeScrollOffset()是判斷滑動是否完成澡匪,如果沒有完成,就會調(diào)用scrollTo褒链,將view滑動到當(dāng)前位置唁情,然后再postInvalidate繼續(xù)調(diào)用draw方法,最終將View一點一點移動到目標位置甫匹。

實例演示

我們要實現(xiàn)的是一個很簡單的例子甸鸟,自定義一個圓形,當(dāng)手指按下的時候兵迅,圓形移動到手指的位置哀墓,手指移動的時候,圓形會跟隨手指移動喷兼,抬起手指的時候篮绰,圓形慢慢的回復(fù)到初始位置。
代碼如下:

public class FollowFingerView extends View{

    //繪制圓形
    private Paint mPaint;

    //繪制背景
    private Paint mBackGroundPaint;
    //View的寬和高
    private int mWidth;
    private int mHeight;
    //定義Scroller
    private Scroller mScroller;
    //存儲上次View的位置參數(shù)
    private int mLastX;
    private int mLastY;
    
    public FollowFingerView(Context context) {
        this(context,null);
        // TODO Auto-generated constructor stub
    }
    public FollowFingerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        // TODO Auto-generated constructor stub
    }
    private void init(){
        mPaint = new Paint();
//設(shè)置圓形顏色
        mPaint.setColor(0x22ff0000);
        mBackGroundPaint=new Paint();
//設(shè)置背景顏色
        mBackGroundPaint.setColor(0xfff8efe0);
        mScroller = new Scroller(getContext());
//設(shè)置默認寬高季惯,wrap_content時使用
        mWidth = 400;
        mHeight = 400;
    }
@Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
//繪制背景
        canvas.drawPaint(mBackGroundPaint);
    //繪制半徑為30像素的圓形
        int radius = 30;
        canvas.drawCircle(30,  30, radius, mPaint);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
//處理wrap_content失效
        setMeasuredDimension(measureWidth(widthMode,width), measureHeight(heightMode,height));
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
  //獲取觸發(fā)事件時吠各,手指的觸碰位置
        int x = (int) event.getX();
        int y = (int) event.getY();
        
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //手指按下時,移動View到觸碰位置
            scrollTo(-x, -y);
            break;
        case MotionEvent.ACTION_MOVE:
//事件發(fā)生時手指的位置與上一個事件結(jié)束時手指的位置勉抓,之間的距離
//注意方向贾漏,可能這樣寫更容易理解:
//int dx = -(x - mLastX);
//int dy = -(y - mLastY);
            int dy = mLastY - y;
            int dx = mLastX - x;
            int dy = mLastY - y;
            //跟隨手指移動
            scrollBy(dx, dy);
            break;
            
        case MotionEvent.ACTION_UP:
//手指抬起的時候,開始返回初始位置
            mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY(), 500);
            Log.d("Follow", "getScrollX is " + getScrollX());
            invalidate();
            break;

        default:
            break;
        }
//記錄事件結(jié)束時手指的位置
        mLastX = x;
        mLastY = y;
    //該View不是clickable的藕筋,返回值默認為false纵散,應(yīng)該手動改為true,否則不能消費事件,只能執(zhí)行down
    //return super.onTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        // TODO Auto-generated method stub
        if(mScroller.computeScrollOffset()){
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

    private int measureWidth(int widthMode,int widthSize){
        switch (widthMode) {
        
        case MeasureSpec.EXACTLY:
            mWidth=widthSize;
            //Log.d("ViewConstructor", "mode is exactly");
            break;
        
        case MeasureSpec.UNSPECIFIED:
        case MeasureSpec.AT_MOST:
            break;
        default:
            break;
        }
        return mWidth;
    }
    
    private int measureHeight(int heightMode,int heightSize){
        
        switch (heightMode) {
        
        case MeasureSpec.EXACTLY:
            mHeight=heightSize;
            break;
            
        case MeasureSpec.UNSPECIFIED:
        case MeasureSpec.AT_MOST:
            break;
        default:
            break;
        }
        return mHeight;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伍掀,一起剝皮案震驚了整個濱河市掰茶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蜜笤,老刑警劉巖濒蒋,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異把兔,居然都是意外死亡沪伙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門县好,熙熙樓的掌柜王于貴愁眉苦臉地迎上來围橡,“玉大人,你說我怎么就攤上這事缕贡∧呈危” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵善绎,是天一觀的道長黔漂。 經(jīng)常有香客問我,道長禀酱,這世上最難降的妖魔是什么炬守? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮剂跟,結(jié)果婚禮上减途,老公的妹妹穿的比我還像新娘。我一直安慰自己曹洽,他們只是感情好鳍置,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著送淆,像睡著了一般税产。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上偷崩,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天辟拷,我揣著相機與錄音,去河邊找鬼阐斜。 笑死衫冻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谒出。 我是一名探鬼主播隅俘,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼邻奠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了为居?” 一聲冷哼從身側(cè)響起碌宴,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎颜骤,沒想到半個月后唧喉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捣卤,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡忍抽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了董朝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸠项。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖子姜,靈堂內(nèi)的尸體忽然破棺而出祟绊,到底是詐尸還是另有隱情,我是刑警寧澤哥捕,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布牧抽,位于F島的核電站,受9級特大地震影響遥赚,放射性物質(zhì)發(fā)生泄漏扬舒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一凫佛、第九天 我趴在偏房一處隱蔽的房頂上張望讲坎。 院中可真熱鬧,春花似錦愧薛、人聲如沸晨炕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓮栗。三九已至,卻和暖如春瞄勾,著一層夾襖步出監(jiān)牢的瞬間遵馆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工丰榴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留货邓,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓四濒,卻偏偏與公主長得像换况,于是被迫代替她去往敵國和親职辨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 內(nèi)容是博主照著書敲出來的戈二,博主碼字挺辛苦的舒裤,轉(zhuǎn)載請注明出處,后序內(nèi)容陸續(xù)會碼出觉吭。 當(dāng)了解了Android坐標系和觸...
    Blankj閱讀 6,641評論 3 61
  • 一腾供、Android開發(fā)初體驗 二、Android與MVC設(shè)計模式模型對象存儲著應(yīng)用的數(shù)據(jù)和業(yè)務(wù)邏輯鲜滩。模型類通常用來...
    為夢想戰(zhàn)斗閱讀 886評論 0 3
  • 背景 這是一個滑動幫助類伴鳖,并不可以使View真正的滑動,而是根據(jù)時間的流逝徙硅,獲取插值器中的數(shù)據(jù)榜聂,傳遞給我們,讓我們...
    anmi7閱讀 784評論 0 1
  • 長歌當(dāng)哭嗓蘑,為生命中那些終將逝去的人和事化為塵土须肆;長歌當(dāng)哭,為那些似水流年桩皿、如花美眷豌汇,終散作云煙。 流光容易把人拋,紅了
    忽悠你的歌閱讀 248評論 0 1
  • 01 風(fēng)和,日暖梅尤。 蘇柒的心情極差柜思。這已經(jīng)是她相的第三十次親了。 蘇柒看著鏡子里的自己巷燥,那張臉眉目清秀赡盘,個子不高,...
    木陶眠閱讀 284評論 3 6