ExpandableListView + SimpleCursorTreeAdapter

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

ExpandableListView使用方法详解_会飞的鱼儿android的博客-CSDN博客_expandablelistview

 2.5.5 ExpandableListView(可折叠列表)的基本使用 | 菜鸟教程

SimpleCursorTreeAdapter_海天鹰的博客-CSDN博客

完整代码:GitLink | 确实开源 

package com.hty.browser;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.SimpleCursorTreeAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Field;
import java.util.ArrayList;

public class FavoriteActivity1 extends Activity {
    ExpandableListView expandableListView;
    int position = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_favorite1);
        expandableListView = (ExpandableListView) findViewById(R.id.expandablelistView);

        expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
            @Override
            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
                String url = ((TextView) v.findViewById(R.id.website)).getText().toString();
                Intent intent = new Intent(FavoriteActivity1.this, MainActivity.class);
                intent.putExtra("url", url);
                setResult(RESULT_OK, intent);
                finish();
                return true;
            }
        });

        expandableListView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
            @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
                ExpandableListView.ExpandableListContextMenuInfo info = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
                int type = ExpandableListView.getPackedPositionType(info.packedPosition);
                if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
                    String title = ((TextView) info.targetView.findViewById(android.R.id.text1)).getText().toString();
                    menu.setHeaderIcon(android.R.drawable.edit_text);
                    menu.setHeaderTitle("分类:" + title);
                    String[] sm = { "修改", "删除" };
                    for (int i=0; i<sm.length; i++) {
                        menu.add(0, i, i, sm[i]);
                    }
                } else if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
                    String title = ((TextView) info.targetView.findViewById(R.id.title)).getText().toString();
                    menu.setHeaderIcon(R.drawable.link);
                    menu.setHeaderTitle(title);
                    String[] sm = { "在新窗口中打开", "复制链接", "分享", "修改", "删除" };
                    for (int i=0; i<sm.length; i++) {
                        menu.add(1, i, i, sm[i]);
                    }
                }
            }
        });

        DBHelper helper = new DBHelper(this);
        Cursor groupCursor = helper.category("");
        SimpleCursorTreeAdapter adapter = new MyExpandableListAdapter(groupCursor, this, android.R.layout.simple_expandable_list_item_1, R.layout.favorite_row, new String[] { "category" }, new int[] { android.R.id.text1 }, new String[] { "_id", "title", "website", "category", "website" }, new int[] { R.id.id, R.id.title, R.id.website, R.id.category, R.id.imageView_favicon });
        adapter.setViewBinder(new SimpleCursorTreeAdapter.ViewBinder(){
            public boolean setViewValue(View view, Cursor cursor, int columnIndex){
                //Log.e(Thread.currentThread().getStackTrace()[2] + "", view.toString() + columnIndex);
                if (view.getId() == R.id.imageView_favicon) {
                    String website = cursor.getString(columnIndex);
                    if (website.startsWith("https://")) {
                        ((ImageView) view).setImageResource(android.R.drawable.ic_secure);
                    } else if (website.startsWith("http://")) {
                        ((ImageView) view).setImageResource(android.R.drawable.ic_partial_secure);
                    } else if (website.startsWith("file://")) {
                        ((ImageView) view).setImageResource(android.R.drawable.stat_notify_sdcard);
                    } else {
                        ((ImageView) view).setImageResource(R.drawable.network);
                    }
                    return true;
                }
                return false;
            }
        });
        expandableListView.setAdapter(adapter);
    }

    public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {
        public MyExpandableListAdapter(Cursor cursor, Context context, int groupLayout, int childLayout, String[] groupFrom, int[] groupTo, String[] childrenFrom, int[] childrenTo) {
            super(context, cursor, groupLayout, groupFrom, groupTo, childLayout, childrenFrom, childrenTo);
        }

        //二级项数据
        @Override
        protected Cursor getChildrenCursor(Cursor groupCursor) {
            String s = groupCursor.getString(groupCursor.getColumnIndex("category"));
            DBHelper helper = new DBHelper(FavoriteActivity1.this);
            Cursor cursor = helper.queryCategoty(s);
            return cursor;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        String[] sm = { "新建分类", "分享数据库", "导出HTML", "导出CSV" };
        for (int i=0; i<sm.length; i++) {
            menu.add(0, i, i, sm[i]);
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        switch (id) {
            case 0:
                AlertDialog.Builder builder = new AlertDialog.Builder(FavoriteActivity1.this);
                builder.setIcon(android.R.drawable.ic_input_add);
                builder.setTitle("新建分类");
                final EditText editText1 = new EditText(this);
                builder.setView(editText1);
                builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        String s = editText1.getText().toString();
                        DBHelper helper = new DBHelper(getApplicationContext());
                        Cursor cursor = helper.category(s);
                        if (cursor.getCount() == 0) {
                            ContentValues values = new ContentValues();
                            values.put("category", s);
                            long i = helper.insert("category", values);
                            if (i != -1)
                                onCreate(null);
                            else
                                Toast.makeText(getApplicationContext(), "新建分类失败", Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(getApplicationContext(), "分类已存在", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
                builder.setNegativeButton("取消", null);
                builder.create().show();
                break;
            case 1:
                File file = new File(DBHelper.DATABASE_NAME);
                if (file.exists()) {
                    Intent intent = new Intent();
                    intent.setAction(Intent.ACTION_SEND);
                    intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
                    intent.setType("*/*");
                    startActivity(Intent.createChooser(intent, "分享 " + DBHelper.filename));
                } else {
                    Toast.makeText(getApplicationContext(), "数据库文件不存在", Toast.LENGTH_SHORT).show();
                }
                break;
            case 2:
                DBHelper helper = new DBHelper(getApplicationContext());
                Cursor cursor = helper.query("");
                String s = "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\"/>\n<title>收藏夹</title>\n<style>\na { text-decoration: none; }\ntable { table-layout: fixed; width: 100%; border-collapse: collapse; }\nth, td { border: 1px solid black; padding: 5px; overflow: hidden; text-overflow: ellipsis; }\ntd:nth-child(3) { white-space: nowrap; }\n</style>\n</head>\n<body>\n<h2 align=center>收藏夹" + cursor.getCount() + "</h2>\n<table>\n<tr><th>标题</th><th>网址</th><th>分类</th></tr>\n";
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String title1 = cursor.getString(cursor.getColumnIndex("title"));
                        String website = cursor.getString(cursor.getColumnIndex("website"));
                        String category = cursor.getString(cursor.getColumnIndex("category"));
                        s = s + "<tr><td>" + title1 + "</td><td><a href=\"" + website + "\" target=\"_blank\">" + website + "</a></td><td>" + category + "</td></tr>\n";
                    }
                }
                s += "</table>\n</body>\n</html>";
                writeFile("webfav.htm", s);
                break;
            case 3:
                s = "";
                helper = new DBHelper(getApplicationContext());
                cursor = helper.query("");
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String title1 = cursor.getString(cursor.getColumnIndex("title"));
                        String website = cursor.getString(cursor.getColumnIndex("website"));
                        String category = cursor.getString(cursor.getColumnIndex("category"));
                        s = s + title1.replace(",", ",") + "," + website + "," + category + "\n";
                    }
                }
                writeFile("webfav.csv", s);
                break;
            case android.R.id.home:
                finish();
                break;
        }
        return true;
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        ExpandableListView.ExpandableListContextMenuInfo menuInfo = (ExpandableListView.ExpandableListContextMenuInfo) item.getMenuInfo();
        position = expandableListView.getFirstVisiblePosition();
        switch (item.getGroupId()) {
            case 0:
                final String category0 = ((TextView) menuInfo.targetView.findViewById(android.R.id.text1)).getText().toString();
                switch (item.getItemId()) {
                    case 0:
                        AlertDialog.Builder builder = new AlertDialog.Builder(FavoriteActivity1.this);
                        builder.setIcon(android.R.drawable.ic_menu_edit);
                        builder.setTitle("分类:" + category0);
                        final EditText editText_rename = new EditText(FavoriteActivity1.this);
                        editText_rename.setText(category0);
                        editText_rename.setSelection(category0.length());
                        builder.setView(editText_rename);
                        builder.setPositiveButton("重命名", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                DBHelper helper = new DBHelper(getApplicationContext());
                                SQLiteDatabase db = helper.getWritableDatabase();
                                ContentValues values = new ContentValues();
                                String category = editText_rename.getText().toString();
                                values.put("category", category);
                                db.update("category", values, "category = '" + category0 + "'", null);
                                db.update(helper.TableName, values, "category = '" + category0 + "'", null);
                                onCreate(null);
                            }
                        });
                        builder.setNegativeButton("取消", null);
                        builder.create().show();
                        break;
                    case 1:
                        DBHelper helper = new DBHelper(getApplicationContext());
                        SQLiteDatabase db = helper.getWritableDatabase();
                        db.delete("category", "category=?", new String[] { category0 });
                        ContentValues values = new ContentValues();
                        values.put("category", "");
                        db.update(helper.TableName, values, "category = '" + category0 + "'", null);
                        onCreate(null);
                        break;
                }
                break;
            case 1:
                final String sid = ((TextView) menuInfo.targetView.findViewById(R.id.id)).getText().toString();
                final String title = ((TextView) menuInfo.targetView.findViewById(R.id.title)).getText().toString();
                final String url = ((TextView) menuInfo.targetView.findViewById(R.id.website)).getText().toString();
                final String category = ((TextView) menuInfo.targetView.findViewById(R.id.category)).getText().toString();
                switch (item.getItemId()) {
                    case 0:
                        Intent intent = new Intent(FavoriteActivity1.this, MainActivity.class);
                        intent.putExtra("url", url);
                        intent.putExtra("newWindow", true);
                        setResult(RESULT_OK, intent);
                        finish();
                        break;
                    case 1:
                        ClipboardManager CM = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
                        CM.setPrimaryClip(ClipData.newPlainText("link", url));
                        Toast.makeText(getApplicationContext(), "链接已复制", Toast.LENGTH_SHORT).show();
                        break;
                    case 2:
                        intent = new Intent();
                        intent.setAction(Intent.ACTION_SEND);
                        intent.putExtra(Intent.EXTRA_TEXT, title + "\n" + url);
                        intent.setType("text/plain");
                        startActivity(Intent.createChooser(intent, "分享"));
                        break;
                    case 3:
                        LinearLayout layout = new LinearLayout(FavoriteActivity1.this);
                        layout.setOrientation(LinearLayout.VERTICAL);
                        final EditText editText_title = new EditText(FavoriteActivity1.this);
                        editText_title.setMaxLines(3);
                        editText_title.setHint("标题");
                        editText_title.setText(title);
                        layout.addView(editText_title);
                        final EditText editText_url = new EditText(FavoriteActivity1.this);
                        editText_url.setMaxLines(5);
                        editText_title.setHint("网址");
                        editText_url.setText(url);
                        layout.addView(editText_url);
                        final Spinner spinner = new Spinner(this);
                        ArrayList<String> list = new ArrayList<>();
                        list.add("");
                        DBHelper helper = new DBHelper(this);
                        Cursor cursor = helper.category("");
                        if (cursor != null) {
                            while (cursor.moveToNext()) {
                                String s = cursor.getString(cursor.getColumnIndex("category"));
                                list.add(s);
                            }
                        }
                        ArrayAdapter adapter = new ArrayAdapter(getApplicationContext(), android.R.layout.simple_spinner_item, list);
                        spinner.setAdapter(adapter);
                        spinner.setSelection(list.indexOf(category));
                        layout.addView(spinner);
                        AlertDialog.Builder builder = new AlertDialog.Builder(FavoriteActivity1.this);
                        builder.setIcon(android.R.drawable.btn_star_big_on);
                        builder.setTitle("修改收藏");
                        builder.setView(layout);
                        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                String stitle = editText_title.getText().toString();
                                String surl = editText_url.getText().toString();
                                Field field = null;
                                try {
                                    //通过反射获取dialog中的私有属性mShowing
                                    field = dialog.getClass().getSuperclass().getDeclaredField("mShowing");
                                    field.setAccessible(true);//设置该属性可以访问
                                } catch (Exception ex) {
                                }
                                if (!stitle.equals("") && (surl.startsWith("http") || !surl.startsWith("file:///"))) {
                                    DBHelper dbHelper = new DBHelper(getApplicationContext());
                                    SQLiteDatabase db = dbHelper.getWritableDatabase();
                                    ContentValues values = new ContentValues();
                                    values.put("website", surl);
                                    values.put("title", stitle);
                                    values.put("category", spinner.getSelectedItem().toString());
                                    int i = db.update(DBHelper.TableName, values, "_id = " + sid, null);
                                    if (i != -1)
                                        onCreate(null);
                                    else
                                        Toast.makeText(getApplicationContext(), "修改失败", Toast.LENGTH_SHORT).show();
                                    try {
                                        //关闭
                                        field.set(dialog, true);
                                        dialog.dismiss();
                                    } catch (Exception ex) {
                                    }
                                } else {
                                    if (stitle.equals("")) {
                                        editText_title.setError("标题不能为空!");
                                    }
                                    if (!surl.startsWith("http://") || !surl.startsWith("https://") || !surl.startsWith("file://")) {
                                        editText_url.setError("网址错误!");
                                    }
                                    try {
                                        //设置dialog不可关闭
                                        field.set(dialog, false);
                                        dialog.dismiss();
                                    } catch (Exception ex) {
                                    }
                                }
                            }
                        });
                        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Field field = null;
                                try {
                                    //通过反射获取dialog中的私有属性mShowing
                                    field = dialog.getClass().getSuperclass().getDeclaredField("mShowing");
                                    field.setAccessible(true);//设置该属性可以访问
                                } catch (Exception e) {
                                }
                                try {
                                    field.set(dialog, true);
                                    dialog.dismiss();
                                } catch (Exception e) {
                                }
                            }
                        });
                        builder.create().show();
                        break;
                    case 4:
                        position = expandableListView.getFirstVisiblePosition();
                        int id = Integer.parseInt(((TextView) menuInfo.targetView.findViewById(R.id.id)).getText().toString());
                        helper = new DBHelper(getApplicationContext());
                        int i = helper.del(id);
                        if (i != -1)
                            onCreate(null);
                        else
                            Toast.makeText(getApplicationContext(), "删除失败", Toast.LENGTH_SHORT).show();
                        break;
                    case 5:
                        builder = new AlertDialog.Builder(FavoriteActivity1.this);
                        builder.setIcon(android.R.drawable.ic_menu_edit);
                        builder.setTitle(title);
                        final EditText editText_rename = new EditText(FavoriteActivity1.this);
                        editText_rename.setText(title);
                        editText_rename.setSelection(title.length());
                        builder.setView(editText_rename);
                        builder.setPositiveButton("重命名", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                DBHelper helper = new DBHelper(getApplicationContext());
                                SQLiteDatabase db = helper.getWritableDatabase();
                                ContentValues values = new ContentValues();
                                String category = editText_rename.getText().toString();
                                values.put("category", category);
                                db.update("category", values, "category = '" + title + "'", null);
                                db.update(helper.TableName, values, "category = '" + title + "'", null);
                                onCreate(null);
                            }
                        });
                        break;
                    case 6:
                        helper = new DBHelper(getApplicationContext());
                        SQLiteDatabase db = helper.getWritableDatabase();
                        db.delete("category", "category=?", new String[]{title});
                        ContentValues values = new ContentValues();
                        values.put("category", "");
                        db.update(helper.TableName, values, "category = '" + title + "'", null);
                        onCreate(null);
                        break;
                }
                break;
        }
        return true;
    }

    void writeFile(String filename, String s) {
        File file = new File(MainActivity.dir, filename);
        try {
            BufferedWriter BW = new BufferedWriter(new FileWriter(file, false)); //false覆盖
            if (filename.endsWith(".csv")) {
                BW.write('\ufeff'); // Excel通过文件的BOM头来判断文件编码
                BW.flush();
            }
            BW.write(s);
            BW.flush();
            Toast.makeText(getApplicationContext(), "写文件 " + MainActivity.dir + File.separator + filename + " 成功", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            Log.e(Thread.currentThread().getStackTrace()[2] + "", e.toString());
            Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
        }
    }

}

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值