(七)仿微信發(fā)布朋友圈拖拽刪除

效果圖如下:


demo7.gif

實現(xiàn)過程:

1.先從布局入手匣缘。要實現(xiàn)recyclerview全屏的拖拽蚓土,布局思路一定要正確掺出。布局關(guān)系如下:


布局關(guān)系圖.png

布局有一點需要注意:
recyclerview高度必須match_parent忆首,這樣才能全屏拖拽忠藤,但是為什么又要位于 editText之下呢阅爽。
這樣是為了防止editText焦點被奪取路幸,無法輸入。位于editText之下后recyclerview又怎么滑出自己的布局呢付翁,這時需要一個屬性設(shè)置clipChildren=false.允許子View超出父View劝赔。

2.拖拽功能實現(xiàn)。 利用ItemTouchHelper

(1)自定義一個類集成并實現(xiàn)ItemTouchHelper.Callback(功能核心,代碼里有注釋)

/**
 * created by dalang at 2018/11/26
 * 微信拖拽排序刪除
 */
public class WXTouchHelper extends ItemTouchHelper.Callback {

    private int dragFlags;
    private int swipeFlags;
    private BGARecyclerViewAdapter adapter;
    private List<String> imagesList;//圖片的順序與拖拽順序保持一致
    private boolean up;//手指抬起標(biāo)記位
    private NestedScrollView scrollView;

    public WXTouchHelper(BGARecyclerViewAdapter adapter, List<String> imagesList, NestedScrollView scrollView) {
        this.adapter = adapter;
        this.imagesList = imagesList;
        this.scrollView=scrollView;
    }

    /**
     * 設(shè)置item是否處理拖拽事件和滑動事件胆敞,以及拖拽和滑動操作的方向
     *
     * @param recyclerView
     * @param viewHolder
     * @return
     */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        //判斷 recyclerView的布局管理器數(shù)據(jù)
        if (recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {//設(shè)置能拖拽的方向

            dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

            swipeFlags = 0;//0則不響應(yīng)事件
        }
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    /**
     * 當(dāng)用戶從item原來的位置拖動可以拖動的item到新位置的過程中調(diào)用
     *
     * @param recyclerView
     * @param viewHolder
     * @param target
     * @return
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder 
    viewHolder, RecyclerView.ViewHolder target) {
        int fromPosition = viewHolder.getAdapterPosition();//得到item原來的position
        int toPosition = target.getAdapterPosition();//得到目標(biāo)position
        //因為沒有將 +號的圖片 加入imageList,所以不用imageList.size-1 此處限制不能移動到recyclerView最后一位
        if (toPosition == imagesList.size()  || imagesList.size()  == fromPosition) {
            return false;
        }
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {

                Collections.swap(imagesList, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {

                Collections.swap(imagesList, i, i - 1);
            }
        }
        adapter.notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    /**
     * 設(shè)置是否支持長按拖拽
     * 此處必須返回false
     * 需要在recyclerView長按事件里限制,否則最后+號長按后扔可拖拽
     * @return
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return false;
    }

    /**
     * @param viewHolder
     * @param direction
     */
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {

    }

    /**
     * 當(dāng)用戶與item的交互結(jié)束并且item也完成了動畫時調(diào)用
     *
     * @param recyclerView
     * @param viewHolder
     */
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        adapter.notifyDataSetChanged();
        initData();
        if (dragListener != null) {
            dragListener.clearView();
        }
    }

    /**
     * 重置
     */
    private void initData() {
        if (dragListener != null) {
            dragListener.deleteState(false);
            dragListener.dragState(false);
        }
        up = false;
    }

    /**
     * 自定義拖動與滑動交互
     *
     * @param c
     * @param recyclerView
     * @param viewHolder
     * @param dX
     * @param dY
     * @param actionState
     * @param isCurrentlyActive
     */
    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
    float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (null == dragListener) {
            return;
        }
       //recyclerview上面的editText的高度為100
        int editTextHeight=ToastUtil.getContext().getResources().getDimensionPixelSize(R.dimen.dimen_100);
      //刪除按鈕高度
        int buttonHeight=ToastUtil.getContext().getResources().getDimensionPixelSize(R.dimen.dimen_50);
        /**
         * item間隔10dp,因為item的xml布局中有個10dp的空白着帽,
         * 拖拽時是拖拽整個itemView所有導(dǎo)致底部10dp空白先接觸刪除按鈕所以在判斷閾值時應(yīng)該考慮此10dp,
         * 如果是采用addItemDecoration添加分割線就不用考慮這10dp杂伟,但是拖拽時會出現(xiàn)分割線遮擋的情況,具體效果可以自己實驗一下
         */
        int spaceHeight=ToastUtil.getContext().getResources().getDimensionPixelSize(R.dimen.dimen_10);//
        /**
         * scrollView.getHeight()-editTextHeight 為recyclerview的高度
         * 此處不用onChildDraw里的參數(shù)recyclerView.getHeight來計算,因為當(dāng)添加圖片至超出屏幕高度
         * 即scrollView可以滑動后獲取的recyclerview不準(zhǔn)確,親測仍翰。
         */
        if (dY>=(scrollView.getHeight()-editTextHeight)
                - viewHolder.itemView.getBottom()//item底部距離recyclerView頂部高度
                -buttonHeight
                +scrollView.getScrollY()
                +spaceHeight) {//拖到刪除處
            dragListener.deleteState(true);
            if (up) {//在刪除處放手赫粥,則刪除item
                //先設(shè)置不可見,如果不設(shè)置的話予借,會看到viewHolder返回到原位置時才消失
              //越平,因為remove會在viewHolder動畫執(zhí)行完成后才將viewHolder刪除
                viewHolder.itemView.setVisibility(View.INVISIBLE);
                imagesList.remove(viewHolder.getAdapterPosition());
                dragListener.deleteOk();
                adapter.notifyItemRemoved(viewHolder.getAdapterPosition());
                initData();
                return;
            }
        } else {//沒有到刪除處
          //如果viewHolder不可見,則表示用戶放手灵迫,重置刪除區(qū)域狀態(tài)
            if (View.INVISIBLE == viewHolder.itemView.getVisibility()) {
                dragListener.dragState(false);
            }
            dragListener.deleteState(false);
        }
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
    }

    /**
     * 當(dāng)長按選中item的時候(拖拽開始的時候)調(diào)用
     *
     * @param viewHolder
     * @param actionState
     */
    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (ItemTouchHelper.ACTION_STATE_DRAG == actionState && dragListener != null) {
            dragListener.dragState(true);
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    /**
     * 設(shè)置手指離開后ViewHolder的動畫時間秦叛,在用戶手指離開后調(diào)用
     *
     * @param recyclerView
     * @param animationType
     * @param animateDx
     * @param animateDy
     * @return
     */
    @Override
    public long getAnimationDuration(RecyclerView recyclerView, int animationType, 
    float animateDx, float animateDy) {
        //手指放開
        up = true;
        return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
    }

    public interface DragListener {
        /**
         * 用戶是否將 item拖動到刪除處,根據(jù)狀態(tài)改變顏色
         *
         * @param delete
         */
        void deleteState(boolean delete);

        /**
         * 是否于拖拽狀態(tài)
         *
         * @param start
         */
        void dragState(boolean start);

        /**
         * 當(dāng)用戶與item的交互結(jié)束并且item也完成了動畫時調(diào)用
         */
        void clearView();


        /**
         * 當(dāng)刪除完成后調(diào)用
         */
        void deleteOk();
    }

    private DragListener dragListener;

    public void setDragListener(DragListener dragListener) {
        this.dragListener = dragListener;
    }

(2)activity調(diào)用及處理

拖拽事件開啟

      //綁定recyclerview
        WXTouchHelper myCallBack = new WXTouchHelper(photoPublishAdapter, imgSelected,scrollView);
        itemTouchHelper = new ItemTouchHelper(myCallBack);
        itemTouchHelper.attachToRecyclerView(recyclerPhoto);


        recyclerPhoto.addOnItemTouchListener(new OnRecyclerItemClickListener(recyclerPhoto) {
            @Override
            public void onItemClick(RecyclerView.ViewHolder viewHolder) {
                if (viewHolder.getAdapterPosition() == imgSelected.size()) {
                    DialogUtil.uploadMultiplePhoto(mActivity, getTakePhoto(), limit);
                } else {
                if (imgSelected.size() != 0) {
                    Intent intent = new Intent(mActivity, BigPhotoActivity.class);
                    intent.putStringArrayListExtra("imgUrls", (ArrayList<String>) imgSelected);
                    intent.putExtra("position", viewHolder.getAdapterPosition());
                    mSwipeBackHelper.forward(intent);
                }
                }
            }

        //長按事件中開啟拖拽 需要判斷position不是+號圖片
            @Override
            public void onLongClick(RecyclerView.ViewHolder viewHolder) {
                if (viewHolder.getAdapterPosition() != imgSelected.size()) {
                    BGAKeyboardUtil.closeKeyboard(mActivity);
                    itemTouchHelper.startDrag(viewHolder);
                }
            }
        });

刪除按鈕顯示

  myCallBack.setDragListener(new WXTouchHelper.DragListener() {
            @Override
            public void deleteState(boolean delete) {
                if (delete) {
                    tvDelete.setAlpha(0.8f);
                    tvDelete.setText("松手即可刪除");
                } else {
                    tvDelete.setAlpha(0.5f);
                    tvDelete.setText("拖到此處刪除");
                }
            }

            @Override
            public void dragState(boolean start) {
                if (start) {
                    tvDelete.setVisibility(View.VISIBLE);
                } else {
                    tvDelete.setVisibility(View.GONE);
                }
            }

            @Override
            public void clearView() {
              //刪除圖片后需要重新計算recyclerview下面布局的margin
                fixBottom();

            }

            @Override
            public void deleteOk() {
                //刪除后重新計算圖片選擇數(shù)量
                limit = 9 - imgSelected.size();

            }
        });

底部布局處理

   /**
     * 處理recyclerView下面的布局
     */
    private void fixBottom() {

        int row = photoPublishAdapter.getItemCount() / 3;
        row = (0 == photoPublishAdapter.getItemCount() % 3) ? row : row + 1;//少于3為1行
        row = (4 == row) ? 3 : row;//最多為三行

        int width = DisplayUtil.getScreenWidth(mActivity);
        int itemWidth = (int) (width - getResources().getDimension(R.dimen.dimen_60)) / 3;//item寬高
        int itemSpace=(int) getResources().getDimension(R.dimen.dimen_10);//item間隔
        int marginTop = (getResources().getDimensionPixelSize(R.dimen.recycle_margin_top)
                + itemWidth * row
                +itemSpace*(row-1)
                + getResources().getDimensionPixelSize(R.dimen.bottom_margin_top));
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) llBottom.getLayoutParams();
        params.setMargins(0, marginTop, 0, 0);
        llBottom.setLayoutParams(params);

    }

3.scrollView包裹editText處理其滾動沖突

/**
 * created by dalang at 2018/11/28
 */
@SuppressLint("AppCompatCustomView")
public class EditTextWithScrollView extends EditText {

    //滑動距離的最大邊界
    private int mOffsetHeight;
    //是否到頂或者到底的標(biāo)志
    private boolean mBottomFlag = false;
    private boolean mCanVerticalScroll;

    public EditTextWithScrollView(Context context) {
        super(context);
        init();
    }

    public EditTextWithScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public EditTextWithScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mCanVerticalScroll = canVerticalScroll();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN)
            //如果是新的按下事件瀑粥,則對mBottomFlag重新初始化
            mBottomFlag = false;
        //如果已經(jīng)不要這次事件挣跋,則傳出取消的信號,這里的作用不大
        if (mBottomFlag)
            event.setAction(MotionEvent.ACTION_CANCEL);

        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean result = super.onTouchEvent(event);
        if (mCanVerticalScroll) {
            //如果是需要攔截狞换,則再攔截避咆,這個方法會在onScrollChanged方法之后再調(diào)用一次
            if (!mBottomFlag)
                getParent().requestDisallowInterceptTouchEvent(true);
        } else {
            getParent().requestDisallowInterceptTouchEvent(false);
        }
        return result;
    }

    @Override
    protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
        super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
        if (vert == mOffsetHeight || vert == 0) {
            //這里觸發(fā)父布局或祖父布局的滑動事件
            getParent().requestDisallowInterceptTouchEvent(false);
            mBottomFlag = true;
        }
    }

    /**
     * EditText豎直方向是否可以滾動
     *
     * @return true:可以滾動   false:不可以滾動
     */
    private boolean canVerticalScroll() {
        //滾動的距離
        int scrollY = getScrollY();
        //控件內(nèi)容的總高度
        int scrollRange = getLayout().getHeight();
        //控件實際顯示的高度
        int scrollExtent = getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
        //控件內(nèi)容總高度與實際顯示高度的差值
        mOffsetHeight = scrollRange - scrollExtent+5;

        if (mOffsetHeight == 0) {

            return false;
        }

        return (scrollY > 0) || (scrollY < mOffsetHeight - 1);
    }
}

4.底部文字點擊事件處理


dmo7_1.gif

相關(guān)代碼如下

在 OnRecyclerItemClickListener中添加方法
public abstract void onOtherClick(MotionEvent e);

private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
            if (childViewUnder != null) {
                RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(childViewUnder);
                onItemClick(childViewHolder);
            } else {
          //判斷點擊的不是圖片 走這個方法
                onOtherClick(e);
            }
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
            if (childViewUnder != null) {
                RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(childViewUnder);
                onLongClick(childViewHolder);
            }
        }
    }
//將textview固定高度好計算
    <dimen name="bottom_textview_height">60dp</dimen>
 <TextView
     style="@style/demo6_text_style"
     android:text="所在位置" />
//原有 textview  style更改
  <style name="demo6_text_style">
        <item name="android:gravity">center</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">@dimen/bottom_textview_height</item>
        <item name="android:textColor">@color/black33</item>
        <item name="android:textSize">@dimen/dimen_18</item>
    </style>
//初始化高度屬性
       //textview 高度
        bottomItemHeight = getResources().getDimensionPixelSize(R.dimen.bottom_textview_height);
        //textview之間分割線 高度
        lineSpace = (int) getResources().getDimension(R.dimen.dimen_1);
        //左邊距
        leftMargin = (int)getResources().getDimension(R.dimen.dimen_20);
        //同步到控件 星星的寬度  圖片大小為30dp 左右各留10dp 方便用戶點擊
        starWidth =(int) getResources().getDimension(R.dimen.dimen_50);

//
   private void fixBottom() {
    之前方法省略
        //用于判斷 在每次fix底部布局高度后判斷 注意要減去頂部edittext的高度
        judgeClickMargin = marginTop-getResources().getDimensionPixelSize(R.dimen.edittext_height);

    }

//Activity中處理
      @Override
            public void onOtherClick(MotionEvent e) {
                if (e.getY()>judgeClickMargin) {
                    int between=(int)e.getY()-judgeClickMargin;//判讀觸摸點與 bottom布局分界處的距離

                    int oneItem=(bottomItemHeight+lineSpace);//一個textview+一個分割線的高度
                    LogUtil.e(e.getY()+"---"+judgeClickMargin+"==="+oneItem);
                    if (between>0 && between<=oneItem) {
                        //點擊在第一個textview上 ---所在位置
                        ToastUtil.normal("所在位置");
                    } else if (between>oneItem && between<=2*oneItem) {

                        //點擊在第二個textview上 ---誰可以看
                        ToastUtil.normal("誰可以看");
                    } else if (between>2*oneItem && between<=3*oneItem) {

                        //點擊在第三個textview上 ---提醒誰看
                        ToastUtil.normal("提醒誰看");
                    } else if (between>3*oneItem && between<=4*oneItem && e.getX()>=leftMargin && e.getX()<=(starWidth+leftMargin)) {
                        //點擊星星 同步到空間
                        ToastUtil.normal("同步到空間");
                    }

                }
            }

其他文章鏈接地址:
(一)高斯模糊實現(xiàn)毛玻璃效果丶共享元素動畫 丶地址選擇器
(二)仿京東頂部伸縮漸變丶自定義viewpager指示器丶viewpager3D回廊丶recyclerview瀑布流
(三)RxJava2常用操作符merge、flatmap修噪、zip--結(jié)合MVP架構(gòu)講解
(四)仿支付寶首頁頂部伸縮滑動/中間層下拉刷新
(五)TabLayout+ViewPager懸浮吸頂及刷新數(shù)量動畫顯示
(六)仿QQ首頁drawer/側(cè)滑刪除/浮動imgaeView/角標(biāo)拖拽

將持續(xù)更新.. 不喜勿噴查库,僅個人分享,希望能幫助到你

源碼地址:Github傳送門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黄琼,一起剝皮案震驚了整個濱河市樊销,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脏款,老刑警劉巖现柠,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弛矛,居然都是意外死亡够吩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門丈氓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來周循,“玉大人,你說我怎么就攤上這事万俗⊥宓眩” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵闰歪,是天一觀的道長嚎研。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么临扮? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任论矾,我火速辦了婚禮,結(jié)果婚禮上杆勇,老公的妹妹穿的比我還像新娘贪壳。我一直安慰自己,他們只是感情好蚜退,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布闰靴。 她就那樣靜靜地躺著,像睡著了一般钻注。 火紅的嫁衣襯著肌膚如雪蚂且。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天幅恋,我揣著相機與錄音杏死,去河邊找鬼。 笑死佳遣,一個胖子當(dāng)著我的面吹牛识埋,可吹牛的內(nèi)容都是我干的凡伊。 我是一名探鬼主播零渐,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼系忙!你這毒婦竟也來了诵盼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤银还,失蹤者是張志新(化名)和其女友劉穎风宁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛹疯,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡戒财,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捺弦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饮寞。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖列吼,靈堂內(nèi)的尸體忽然破棺而出幽崩,到底是詐尸還是另有隱情,我是刑警寧澤寞钥,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布慌申,位于F島的核電站,受9級特大地震影響理郑,放射性物質(zhì)發(fā)生泄漏蹄溉。R本人自食惡果不足惜咨油,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望类缤。 院中可真熱鬧臼勉,春花似錦、人聲如沸餐弱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽膏蚓。三九已至瓢谢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間驮瞧,已是汗流浹背氓扛。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留论笔,地道東北人采郎。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像狂魔,于是被迫代替她去往敵國和親蒜埋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,077評論 25 707
  • 用兩張圖告訴你最楷,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料整份? 從這篇文章中你...
    hw1212閱讀 12,714評論 2 59
  • 內(nèi)容 抽屜菜單 ListView WebView SwitchButton 按鈕 點贊按鈕 進度條 TabLayo...
    小狼W閱讀 1,613評論 0 10
  • 原文鏈接:https://github.com/opendigg/awesome-github-android-u...
    IM魂影閱讀 32,930評論 6 472
  • 正好下午休息,打開被我冷落好久的簡書籽孙,找到我收藏的作品開始臨摹烈评,以前幾乎是完全參照,但是這次把花兒畫出以后犯建,下來的...
    起光閱讀 203評論 0 1