0
回答
ListView自定义对话框以及列表形式的切换

看截图:

imageimage

长按后还是显示checkbox。点击view按钮,将出现对话框:

imageimage

如果touch对话框以外的区域,对话框将消失,这就比较类似ios里的popover了。

view mode下的radio按钮,可以切换列表形式,比如从缩略图(默认的模式)转换到列表模式下。

说一下如何实现自定义对话框。大致步骤有:

  • 编写类,继承Dialog
  • 覆盖超类的onTouchEvent方法。基本思路是在该方法中,判断一下touch的坐标是在对话框包含的视图坐标里还是外,如果是外,就hide(或者也可dismess)对话框对象。

代码如下:

class MyDialog extends Dialog {

    public MyDialog(Context context) { 
        super(context); 
    }

    public MyDialog(Context context, boolean cancelable, 
            OnCancelListener cancelListener) { 
        super(context, cancelable, cancelListener); 
    }

    public MyDialog(Context context, int theme) { 
        super(context, theme); 
    }

    /** 
     * 处理触摸事件,如果触摸超出对话框范围,则对话框退出 
     */ 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
        Rect rect = new Rect(); 
        View view = findViewById(R.id.dialogLayout);// 取对话框最外层视图 
        view.getWindowVisibleDisplayFrame(rect);// 得到window的矩形

        // 因为对话框居中,因此对话框相对于window的坐标可通过对话框长和宽以及window矩形计算出来 
        Rect rect2 = new Rect((rect.right – view.getRight()) / 2, 
                (rect.bottom – view.getBottom()) / 2, view.getRight() 
                        + (rect.right – view.getRight()) / 2, 
                view.getBottom() + (rect.bottom – view.getBottom()));

        if (!rect2.contains((int) event.getRawX(), (int) event.getRawY())) { 
            this.dismiss(); 
            return true; 
        } 
        return super.onTouchEvent(event); 
    } 
}

切换表的表现形式,说起来很简单,其实就是为ListView设置不同的adapter即可。即:ListView.setAdapter()方法。每次设置不同的adapter实例,就会即可改变列表的表现形式。

在本例中,因为有数据的变化等因素,代码要复杂很多。

另外,本例使用sqlite数据库替代了大部分原来用数组和列表模拟的数据集合。见com.easymorse.list.datasource包下的三个类,是一个标准的dao实现。dao的代码,主要实现了crud。代码:

/** 
* Record dao对象 
* 
* @author marshal 
* 
*/ 
public class RecordDao {

    @SuppressWarnings("unused") 
    private static final String TAG = "listview";

    // 由于模拟图片数据 
    private static final int[] drawables = { R.drawable.a1, R.drawable.a2, 
            R.drawable.a3, R.drawable.a4, R.drawable.a5, R.drawable.a6, 
            R.drawable.a7, R.drawable.a8, R.drawable.a9, R.drawable.a10, 
            R.drawable.a12, R.drawable.a13 };

    // 图片的缓存,使用SoftReference是为了防止oom 
    private static Map<Long, SoftReference<Drawable>> drawableCache = new HashMap<Long, SoftReference<Drawable>>();

    private Context context;

    private SQLiteDatabase database;

    public RecordDao(Context context) { 
        this.context = context; 
        init(); 
    }

    /** 
     * 通过缓存获取图片对象 
     * 
     * @param id 
     *            图片的id 
     * @return 
     */ 
    public Drawable getDrawable(Long id) { 
        // 如果缓存中有,使用缓存的 
        if (drawableCache.get(id) != null 
                && drawableCache.get(id).get() != null) { 
            return drawableCache.get(id).get(); 
        }

        // 未在缓存中,可能是没加入缓存,也可能是垃圾回收,则重新获取,并加载缓存中 
        if (id >= 1 && id <= drawables.length) { 
            Drawable drawable = context.getResources().getDrawable( 
                    drawables[id.intValue() - 1]); 
            drawableCache.put(id, new SoftReference<Drawable>(drawable)); 
            return drawable; 
        } 
        return null; 
    }

    private void init() { 
        this.database = context.openOrCreateDatabase("mydata", 
                Context.MODE_PRIVATE, null);

        //TODO 正式使用时,取消下面初始化代码,改为使用SQLiteOpenHelper 
        dropTables(); 
        createTables();

        for (int i = 0; i < 12; i++) { 
            create(new Record(null, "柴可夫司机")); 
        } 
    }

    public void create(Record record) { 
        SQLiteStatement statement = database 
                .compileStatement("insert into mydata (name) values(?)"); 
        statement.bindString(1, record.getName()); 
        statement.execute(); 
        statement.close();

        //需要设置record的id,否则没有唯一标识,无法和数据库交互 
        Cursor cursor = database.rawQuery( 
                "select last_insert_rowid() from mydata", new String[] {}); 
        if (cursor.moveToFirst()) { 
            record.setId(cursor.getLong(0)); 
        } 
        cursor.close(); 
    }

    public void browse(Page page) { 
        page.setResults(new ArrayList<Record>()); 
        Cursor cursor = database.rawQuery("select count(*) from mydata ", 
                new String[] {}); 
        if (cursor.moveToFirst()) { 
            page.setCount(cursor.getInt(0)); 
        } 
        cursor.close();

        if (page.getCount() > page.getSize() * (page.getNo() – 1)) { 
            cursor = database.rawQuery( 
                    "select id,name from mydata limit " + page.getSize() 
                            * (page.getNo() – 1) + " , " + page.getSize(), 
                    new String[] {});//使用limit子句

            while (cursor.moveToNext()) { 
                Record record = new Record(cursor.getLong(0), 
                        cursor.getString(1)); 
                page.getResults().add(record); 
            } 
            cursor.close(); 
        } 
    }

    public void delete(Long id) { 
        SQLiteStatement statement = database 
                .compileStatement("delete from mydata where id=?"); 
        statement.bindLong(1, id); 
        statement.execute(); 
        statement.close(); 
    }

    public Record get(Long id) { 
        Record record = null; 
        Cursor cursor = database.rawQuery("select name from mydata where id=" 
                + id, new String[] {}); 
        if (cursor.moveToFirst()) { 
            record = new Record(); 
            record.setName(cursor.getString(0)); 
            record.setId(id); 
        } 
        cursor.close(); 
        return record; 
    }

    private void dropTables() { 
        database.execSQL("drop table if exists mydata"); 
    }

    private void createTables() { 
        database.execSQL("create table if not exists mydata(" 
                + " id integer primary key autoincrement," + " name text" + ")"); 
    } 
}
 

另外,这里做了个简单的缓存Drawable对象,使用SoftReference,软引用,这样当虚拟机内存够用的时候保持在内存中。当内存不足才清除。

源代码见:

http://easymorse.googlecode.com/svn/tags/ListViewDemo-0.8/

举报
华宰
发帖于7年前 0回/1K+阅
顶部