很羞愧的是,第一个有关程序的随笔就是一处我暂时无法解决并解释的问题, 先记录下来吧, 等以后弄明白了再补充.
最近在做一个android端的IMAPP, 通讯协议采用的XMPP(因为时间比较紧,并属于内部软件,一切从简了), 服务器用的openfire二次开发, android端自然就是asmack了, 网上有很多例子, 封装的已经很到位了.
在做的过程中, 聊天页肯定是采用ListView了.大约得效果如下图:
不好意思哈,这个效果图是仿的微信...
大家都用过微信,知道进入聊天界面时,ListView会自动滚动到最新的一条消息, 也就是最后一行.
看起来这个效果应该很好做,因为ListView有很多方法可以做到这一点.
但是...但是...问题来了...
我的做法是
1.首先在XML里设置了
android:transcriptMode="alwaysScroll"
网上对这个属性的解释是: 可以在列表改变的时候自动将最后一行滑到可视范围.
注意是...改变的时候...也就是说如果新加一条数据,或者ListView的大小发现变化的时候(就是点击EditView时弹出键盘时),会出现自动滚屏的效果.
这里不包括初次加载数据时,至少我这里的真机是没有任何效果,对了我以上以下所说的现象都是我个人测试现象,没有任何通用性权威性可言.
继续查百度, 有人说要加上一句
android:stackFromBottom="true"
我加上了, 确实是有效果, 但还是有个问题: 如果ListView的数据量是可以超出一个屏幕的时候, 效果满足, 如果数据量不足一个屏幕就是会出现下面的效果:
那我就考虑通过ListView里数据量来动态设置这个属性
if(...){ lv.setStackFromBottom(true); //默认是false }
满以为这样就可以了.. 是的, 如果是纯文本确实没问题, 但如果有需要异步加载的图片时...问题又来了...我用的开源组件ImageLoader
String mapUrl = Scheme.FILE.wrap(data.getPath());
ImageLoader.getInstance().displayImage(mapUrl, content_img, options);
一旦有图片需要加载,ListView又会显示第一条数据了...怎么办?百度...查到ListView的setSelection(position)方法.我的想法是在设置完适配器后在手动选择最后一行:
listview.setAdapter(adapter);
listview.setSelection(adapter.getCount()-1);
然后现象很是奇怪, activity第一次onCreate时, 滚动条不在最上也不在最下面,在中间的某个位置, 然后按返回键, 再次进入, 就是最下面了...
第一次进入明显滚动条在中间位置,上面第一条显示不完全返回键后,再次进入一切正常了
我觉得原因是第一次因为image异步加载时操作了UI, 导致setSelected()失效, 第二次正常可能是imagLoader有缓存,并没有加载图片...
我实在没有办法了..那我等图片加载完再setSelected()吧.
ImageLoader.getInstance().displayImage(imageUrl, content_img, options, new SimpleImageLoadingListener() { @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { super.onLoadingComplete(imageUri, view, loadedImage); ChatListAdapter.this.listView.setSelection(getCount()-1); } });
这总行了吧...还是有问题...这样的写法在列表滑动过程中如果加载图片了, 会有个跳卡的效果.所以最后还要判断并设置在第一次进入界面时加载图片成功执行上面代码...然后就不执行了...
告诉我, 为什么会做的这么复杂!!! 我把流程贴出来就不怕你们笑话了...求教!!!
-----------------------------------------------------------------------------------------
15-2-26日补充:
之前的做法,始终还是有问题,而且在滑动过程中总是有停顿感.我又想了一下:如果问题是出在异步加载和setSelected()冲突的话,那我可以考虑同步加载啊,反正显示在再聊天框的图片已经在本地SD卡内了.
修改代码为
String imageUrl = Scheme.FILE.wrap(data.getPath()); Bitmap bm = ImageLoader.getInstance().loadImageSync(imageUrl, options); content_img.setImageBitmap(bm);
问题解决了!