rxAndroid 和ActionMode实现简易文件浏览器

ActionMode简介

Android 3.0以前,我们处理列表的长按事件经常使用Context Menu,Android3.0以后,我们有了新的选择:ActionMode。

Android开发者应该都熟悉Context Menu了,Context Menu是悬浮在操作项之上的视图,ActionMode是临时占据了ActionBar的位置。

ActionMode使用步骤

实现ActionMode.Callbak接口,并处理其生命周期方法即可

1.public boolean onCreateActionMode(ActionMode mode, Menu menu)

2.public boolean onPrepareActionMode(ActionMode mode, Menu menu)

3.public boolean onActionItemClicked(ActionMode mode, MenuItem item)

4.public void onDestroyActionMode(ActionMode mode)

重写ActionMode

package com.example.simpleexplore;

import android.app.Activity;

import android.support.v7.view.ActionMode;

import android.view.Menu;

import android.view.MenuItem;

import android.view.Window;

/**

* Created by Administrator on 2017/8/5 0005.

*/

public class ActionModeCallback implements ActionMode.Callback{

    private Activity activity;

    private Window window;

    private ActionListener mActionListener;

    private ActionMode actionMode;

    private boolean isShowing = true;

    public ActionModeCallback(Activity activity,ActionListener listener){

        this.activity = activity;

        this.window = activity.getWindow();

        mActionListener = listener;

    }

    @Override

    public boolean onCreateActionMode(ActionMode mode, Menu menu) {

        actionMode = mode;

        mode.getMenuInflater().inflate(R.menu.menu_item_top,menu);

        return true;

    }

    @Override

    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {

        return false;

    }

    @Override

    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {

        if(item.getItemId() == R.id.menu_item_done){

            if(mActionListener != null){

                mActionListener.onFinishAction();

            }

        }else if(item.getItemId() == R.id.menu_item_delete){

          if(mActionListener != null){

              mActionListener.onDeleteAction();

          }

        }

        mode.finish();

        return false;

    }

    @Override

    public void onDestroyActionMode(ActionMode mode) {

        isShowing = false;

        if(mActionListener != null){

            mActionListener.onDismissAction();

        }

    }

    /**

    * 更新title

    * @param count

    */

    public void updateTitleSelectItemCount(int count){

        if(actionMode != null){

            actionMode.setTitle(count + (count > 1?"items":"item") + "selected");

        }

    }

    /**

    * 退出actionMode

    */

    public void dismiss(){

        if(actionMode != null){

            actionMode.finish();

        }

    }

    /**

    * ActionmMode 是否开启

    */

    public boolean isShowing(){

        return isShowing;

    }

    /**

    * 设置ActionMode的开启

    * @param showing

    */

    public void setShowing(boolean showing){

        isShowing = showing;

    }

    /**

    * actionMode的监听者

    */

    public interface ActionListener {

        void onFinishAction();

        void onDismissAction();

        void onDeleteAction();

    }

}

```

###定义文件model

```

public class FileWraper {

    /**

    * 文件

    */

    public File file;

    /**

    * 是否选中

    */

    public boolean isSelected = false;

    public FileWraper(){

    }

    public FileWraper(File file){

        this.file = file;

    }

    public FileWraper(File file,boolean isSelected){

        this.file = file;

        this.isSelected = isSelected;

    }

}

```

###定义堆栈

存储每次浏览时访问节点的记录

```

public class FileTreeStack {

    //栈顶节点

    private Node mTopNode;

    //栈内元素个数

    private int mSize;

    //入栈

    public void push(FileShotSnap shotSnap){

        Node node = new Node();

        node.shotSnap = shotSnap;

        node.next = mTopNode;

        mTopNode = node;//尾插法

        mSize++;

    }

    //出栈

    public FileShotSnap pop(){

        if(mTopNode == null) return null;

        FileShotSnap shotSnap = mTopNode.shotSnap;

        mTopNode = mTopNode.next;

        mSize--;

        return shotSnap;

    }

    /**

    * 返回堆栈大小

    * @return

    */

    public int size(){

        return mSize;

    }

    //访问节点

    class Node {

        FileShotSnap shotSnap;

        Node next;//指向下一个节点

    }

    public static class FileShotSnap {

        //母文件夹

        public File parent;

        //此文件夹下的文件

        public List files;

        //y上的滑动距离

        public int ScrollY;

    }

}

```

###MainActvity

```

public class FileExploreActivity extends BaseActivity {

    @BindView(R.id.recycler_view)

    RecyclerView recyclerView;

    private int position;

    //根目录

    private File rootFile = Environment.getExternalStorage();

    //文件访问栈

    private FileTreeStack mFileStack;

    private ActionModeCallback mCallback;


//当前状态下的母文件夹

File mCurrentFileParent;

//当前所有文件

List mCurrentFiles;

//选中的文件列表

List mSelectedFiles = new ArrayList<>();

private FileAdapter adapter;

    @Override

    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_file_explore);

        ButterKnife.bind(this);

        initView();

    }

    //回退

    @Override

    public void onBackPressed() {

        if(mFileStack.size() == 0){

            super.onBackPressed();

        }else {

            restoreTreeStack(mFileStack.pop());

        }

    }

    private void initView() {

        adapter = new FileAdapter(this,null);

        adapter.setOnClickListener(new ListAdapter.OnItemClickListener() {

            @Override

            public void onClick(View itemView, int position) {

                //获取选中文件

                FileWraper item = adapter.getItem(position);

                if(item.file.isDirectory()){

                    //如果是在选择状态

                    if(isInModeAction()){

                        //选中或取消文件

                        updateSelectFiles(item,position);

                    }else {

                        //进入文件夹 首先堆栈

                        storeTreeStack();

                        //加载文件

                        loadFiles(item.file);

                        //刷新标题

                        updateTitle();

                    }

                }

            }

        });

        adapter.setOnItemLongClickListener(new ListAdapter.OnItemLongClickListener() {

            @Override

            public void onLongClick(View itemView, int position) {

                FileWraper item = adapter.getItem(position);

                //长按进入选则文件状态

                if(item.file.isDirectory()){

                    if(mCallback == null || !mCallback.isShowing()){

                        startActionMode();

                    }

                    //选中或取消文件

                    updateSelectFiles(item,position);

                }

            }

        });

        recyclerView.setAdapter(adapter);

        //加载音乐

        loadFiles(rootFile);

    }

    private void startActionMode() {

        if(mCallback == null){

            mCallback = new ActionModeCallback(this, new ActionModeCallback.ActionListener() {

                @Override

                public void onFinishAction() {

                    //选中

                    Toast.makeText(FileExploreActivity.this, "选中所有", Toast.LENGTH_SHORT).show();

                    if(mSelectedFiles.size() > 0){

                        //操作

                    } else {

                        mCallback.dismiss();

                    }

                }

                @Override

                public void onDismissAction() {

                    //取消

                    Toast.makeText(FileExploreActivity.this, "取消续重", Toast.LENGTH_SHORT).show();

                    clearSelections();

                }

                @Override

                public void onDeleteAction() {

                    //删除

                    Toast.makeText(FileExploreActivity.this, "删除选中文件", Toast.LENGTH_SHORT).show();

                }

            });

        }

        startSupportActionMode(mCallback);//开启ActionMode ActionBar被替代,进入选择文件状态

        mCallback.setShowing(true);

    }

    //清楚当前所有选中文件

    private void clearSelections() {

        boolean needClear = mSelectedFiles.size() > 0;

        mSelectedFiles.clear();

        if(needClear){

            adapter.clearSelections();

            adapter.notifyDataSetChanged();

        }

    }

    //更新选中或取消

    private void updateSelectFiles(FileWraper fileWraper,int position) {

        if(fileWraper.file.isFile()) return;

        //更新文件选中状态

        fileWraper.isSelected = !fileWraper.isSelected;

        //添加或取消选中

        if(fileWraper.isSelected){

            mSelectedFiles.add(fileWraper.file);

        }else {

            if(mSelectedFiles.indexOf(fileWraper.file) != -1){

                mSelectedFiles.remove(fileWraper.file);

            }

        }

        //更新UI

        adapter.notifyItemChanged(position);

        //更新选中UI

        mCallback.updateTitleSelectItemCount(mSelectedFiles.size());

    }

    /**

    * 更新标题

    */

    private void updateTitle() {

        getSupportActionBar().setTitle(mCurrentFileParent.getName());

    }

    /**

    * 存储节点

    */

    private void storeTreeStack() {

        //把当前节点加入树栈中

        FileTreeStack.FileShotSnap shotSnap = new FileTreeStack.FileShotSnap();

        shotSnap.parent = mCurrentFileParent;

        shotSnap.files = mCurrentFiles;

        mFileStack.push(shotSnap);

    }

    /**

    * 取出节点

    * @param top

    */

    private void restoreTreeStack(FileTreeStack.FileShotSnap top) {

        mCurrentFileParent = top.parent;

        mCurrentFiles = top.files;

        int scrollOffsetY = top.ScrollY;

        adapter.setDate(mCurrentFiles);

        adapter.notifyDataSetChanged();

        recyclerView.scrollTo(0,scrollOffsetY);

    }

    /**

    * 判断是否在选择模式下

    * @return

    */

    private boolean isInModeAction() {

        //如果第一个条件不符合 就直接返回 不会看第二个

        return mCallback != null && mCallback.isShowing();

    }

    /**

    * 加载文件 并更新UI

    */

    private void loadFiles(File parent) {

        //rxAndroid 加载文件

        Subscription subscription = Observable.just(parent)

                .flatMap(new Func1>>() {

                    @Override

                    public Observable> call(File parent) {

                        List files = Arrays.asList(parent.listFiles(SystemFileFilter.DEFAULT_INSTANCE));

                        Collections.sort(files, new Comparator() {

                            @Override

                            public int compare(File f1, File f2) {

                                if (f1.isDirectory() && f2.isFile()) {

                                    return -1;

                                }

                                if (f2.isDirectory() && f1.isFile()) {

                                    return 1;

                                }

                                return f1.getName().compareToIgnoreCase(f2.getName());

                            }

                        });

                        // 创建文件列表

                        List fileWrappers = new ArrayList<>(files.size());

                        for (File file : files) {

                            fileWrappers.add(new FileWrapper(file));

                        }

                        return Observable.just(fileWrappers);

                    }

                })

                .subscribeOn(Schedulers.io())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(new Subscriber>() {

                    @Override

                    public void onCompleted() {


}

                    @Override

                    public void onError(Throwable throwable) {

                        Log.e(TAG, "onError: ", throwable);

                    }

                    @Override

                    public void onNext(List files) {

                        mCurrentFiles = files;

                        onFileLoaded(parent);

                    }

                });

        addSubscription(subscription);

    }

    private void onFileLoaded(File parent) {

        mCurrentFileParent = parent;

        //刷新数据

        adapter.setDate(mCurrentFiles);

        adapter.notifyDataSetChanged();

        //进入文件夹的时候滑动到第一个位置就可以

        recyclerView.scrollTo(0,0);

    }

}
```

适配器及数据的绑定就省略了
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容