自定義DragFrameLayout實現(xiàn)拖動子控件的效果

DragFrameLayout實現(xiàn)拖動子控件的效果

效果圖

這里寫圖片描述

介紹

DragFrameLayout繼承自FrameLayout,可以對其內(nèi)部的子View進行拖曳诞仓,子View的數(shù)量不限,一次只可以拖動一個view速兔。
當然也可以繼承RealtiveLayout

使用步驟

  1. 將這個類DragFrameLayout放入xml中狂芋,里面放入需要拖動的View,
  2. 獲取DragFrameLayout和子View
  3. 將子View作為可拖動的view將入DragFrameLayout中(實際是放入內(nèi)部集合中)

//注意:不是addView(tv),是addDragView(tv)

DragFrameLayout dragFrameLayout = (DragFrameLayout) findViewById(R.id.dragFrameLayout);
TextView tv = (TextView) findViewById(R.id.tv);
dragFrameLayout.addDragView(tv);

DragFrameLayout源碼介紹

  1. 首先我們繼承FrameLayout,需要重寫4個構造方法憨栽,其中4個參數(shù)的構造方法是用于API>=21帜矾,所以翼虫,我們只需要重寫其余3個構造方法即可。
  2. 創(chuàng)建接口用于拖動控件的處理
  3. 事件分發(fā)與攔截
  4. 在其構造方法里面創(chuàng)建ViewDragHelper對象并重寫回調中的方法

第一步:創(chuàng)建拖動回調

下面有完整版代碼屡萤,類和方法的名字可能不同珍剑,但是步驟邏輯處理是一樣的。

public interface OnDragDropListener {
    void onDragDrop(boolean captured);
}

private OnDragDropListener onDragDropListener;

public void setOnDragDropListener(OnDragDropListener onDragDropListener) {
    this.onDragDropListener = onDragDropListener;
}

第二步:重寫構造方法

注意:有一個參數(shù)和兩個參數(shù)的構造方法中用的是this,不是super死陆,這樣會調用3個參數(shù)的構造方法招拙。
在3個參數(shù)的構造方法中創(chuàng)建viewList,用于存放我們要拖動的childView;并對外公開添加的方法
創(chuàng)建ViewDragHelper對象,再起回調中重寫5個方法

回調中重寫的方法 說明
boolean tryCaptureView(View child, int pointerId) 是否捕獲childView: 如果viewList包含child措译,那么捕獲childView别凤;如果不包含child,就不捕獲childView
int clampViewPositionHorizontal(View child, int left, int dx) 到左邊界的距離
int clampViewPositionVertical 到上邊界的距離
onViewCaptured(View capturedChild, int activePointerId) 當捕獲到child后的處理:獲取child的監(jiān)聽
void onViewReleased(View releasedChild, float xvel, float yvel) 當釋放child后的處理:取消監(jiān)聽领虹,不再處理
void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) 不需要重寫
這里寫圖片描述
public class DragFrameLayout extends FrameLayout {
    public DragFrameLayout(@NonNull Context context) {
        this(context,null);
    }

    public DragFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public DragFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //第二步:創(chuàng)建存放View的集合
        viewList = new ArrayList<>();

        dragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {

            /**
             * 是否捕獲childView:
             * 如果viewList包含child规哪,那么捕獲childView
             * 如果不包含child,就不捕獲childView
             */
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return viewList.contains(child);
            }

            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                super.onViewPositionChanged(changedView, left, top, dx, dy);
            }

            /**
             * 當捕獲到child后的處理:
             * 獲取child的監(jiān)聽
             */
            @Override
            public void onViewCaptured(View capturedChild, int activePointerId) {
                super.onViewCaptured(capturedChild, activePointerId);
                if (onDragDropListener != null) {
                    onDragDropListener.onDragDrop(true);
                }
            }

            /**
             * 當釋放child后的處理:
             * 取消監(jiān)聽塌衰,不再處理
             */
            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                super.onViewReleased(releasedChild, xvel, yvel);
                if (onDragDropListener != null) {
                    onDragDropListener.onDragDrop(false);
                }
            }

            /**
             * 到左邊界的距離
             */
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                return left;
            }

            /**
             * 到上邊界的距離
             */
            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                return top;
            }
        });
    }
}

由于viewList是用private修飾的诉稍,所以需要對外公開的添加chiildView的方法

public void addDragChildView(View child) {
    viewList.add(child);
}

第三步:處理事件

需要重寫2個方法:是否攔截事件和自身如何處理事件,分別是:onInterceptTouchEvent(MotionEvent ev)最疆、onTouchEvent(MotionEvent event)

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    //當手指抬起或事件取消的時候 就不攔截事件
    int actionMasked = ev.getActionMasked();
    if (actionMasked == MotionEvent.ACTION_CANCEL || actionMasked == MotionEvent.ACTION_UP) {
        return false;
    }
    return dragHelper.shouldInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    dragHelper.processTouchEvent(event);
    return true;
}

其它

demo:https://git.oschina.net/customView/CustomDragFrameLayout
demo是從google Android Sample中抽取出來的:https://developer.android.google.cn/samples/ElevationDrag/index.html

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末杯巨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子努酸,更是在濱河造成了極大的恐慌服爷,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件获诈,死亡現(xiàn)場離奇詭異仍源,居然都是意外死亡,警方通過查閱死者的電腦和手機烙荷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門镜会,熙熙樓的掌柜王于貴愁眉苦臉地迎上來檬寂,“玉大人终抽,你說我怎么就攤上這事⊥爸粒” “怎么了昼伴?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長镣屹。 經(jīng)常有香客問我圃郊,道長,這世上最難降的妖魔是什么女蜈? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任持舆,我火速辦了婚禮色瘩,結果婚禮上,老公的妹妹穿的比我還像新娘逸寓。我一直安慰自己居兆,他們只是感情好,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布竹伸。 她就那樣靜靜地躺著泥栖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勋篓。 梳的紋絲不亂的頭發(fā)上吧享,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機與錄音譬嚣,去河邊找鬼钢颂。 笑死,一個胖子當著我的面吹牛孤荣,可吹牛的內(nèi)容都是我干的甸陌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼盐股,長吁一口氣:“原來是場噩夢啊……” “哼钱豁!你這毒婦竟也來了?” 一聲冷哼從身側響起疯汁,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤牲尺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后幌蚊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谤碳,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年溢豆,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜒简。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡漩仙,死狀恐怖搓茬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情队他,我是刑警寧澤卷仑,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站麸折,受9級特大地震影響锡凝,放射性物質發(fā)生泄漏。R本人自食惡果不足惜垢啼,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一窜锯、第九天 我趴在偏房一處隱蔽的房頂上張望张肾。 院中可真熱鬧,春花似錦锚扎、人聲如沸捌浩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尸饺。三九已至,卻和暖如春助币,著一層夾襖步出監(jiān)牢的瞬間浪听,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工眉菱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留迹栓,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓俭缓,卻偏偏與公主長得像克伊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子华坦,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,730評論 25 707
  • 內(nèi)容是博主照著書敲出來的愿吹,博主碼字挺辛苦的,轉載請注明出處惜姐,后序內(nèi)容陸續(xù)會碼出犁跪。 當了解了Android坐標系和觸...
    Blankj閱讀 6,632評論 3 61
  • ViewDragHelper實例的創(chuàng)建 ViewDragHelper重載了兩個create()靜態(tài)方法public...
    傀儡世界閱讀 655評論 0 3
  • 迦羅奇楠香, 月銀白歹袁, 春夜三更無眠坷衍。 淺墨桃花箋, 七弦亂条舔, 撫盡滿懷相思枫耳。 孤影中堂, 酒閣只聞籠雀鳴孟抗。 紅松...
    手握瓷杯閱讀 196評論 1 4
  • 有一種感動叫做哭 為一首歌好聽到哭 為女神美到哭 為偶像帥到哭 眼睛沒哭 心卻流下了淚痕 耳朵為了一種聲音哭 眼睛...
    萌龍在天閱讀 181評論 0 1