衔接上文, 动弹的发送(TweetPub.java)其实还有许多功能值得我们学习,动弹界面其实也是一个发微博界面,功能点如下:
1.表情的实现
2.键盘的消隐机制
3.选择图片并处理上传的两张方式 包括拍照和从相册
那么现在就来分析一下具体的实现:
1.表情的实现
这里表情的实现其实很简单,就是一个GridView,那么怎么在edittext中显示表情呢?其实有些基础的大家也应该知道,使用的是SpinnableString和 ImageSpan 代码如下:
//初始化表情控件
private void initGridView() {
mGVFaceAdapter = new GridViewFaceAdapter(this);
mGridView = (GridView)findViewById(R.id.tweet_pub_faces);
mGridView.setAdapter(mGVFaceAdapter);
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//插入的表情
SpannableString ss = new SpannableString(view.getTag().toString());
Drawable d = getResources().getDrawable((int)mGVFaceAdapter.getItemId(position));
d.setBounds(0, 0, 35, 35);//设置表情图片的显示大小
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM);
ss.setSpan(span, 0, view.getTag().toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
//在光标所在处插入表情
mContent.getText().insert(mContent.getSelectionStart(), ss);
}
});
}
表情数据的装载全部在GridViewFaceAdapter里面进行,请自行查看源码,至于表情的显示隐藏,只不过是gridview的显示隐藏而已.
2.键盘的消隐机制.
在做编辑界面的时候,键盘的消隐关于很 影响用户的体验,但是如果添加了一下底部的富编辑按钮, 按照android原有的逻辑,会发现很多时候不想让键盘弹出时候键盘弹出了,比如在表情打开的时候键盘弹出,这样用户体验机会非常差,又比如,键盘弹出的时候吧底部工具类遮住,用户就不能再键盘打开的时候点击选择表情了.这样的体验也是非常差. 故此我们应该出来键盘表情的消隐机制,提高用户的体验.
那么我们就一步一步来看:
首先是键盘 出现后 其他UI空间跟随调整,也就是键盘也可以把底部工具类推上去.其实实现比较简单
在android中添加属性
android:windowSoftInputMode="stateVisible|adjustResize"
第一个属性是进入这个activity就获得焦点 弹出键盘
第二个属性就是键盘弹出 UI空间随之调整了
这里不详细介绍 请参考
android:windowSoftInputMode属性使用
http://www.blogjava.net/zhip/archive/2011/02/14/344258.html
然后是解决键盘弹出和表情panel弹出的冲突:
用户点击编辑器,弹出键盘
//编辑器点击事件
mContent.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//显示软键盘
showIMM();
}
});
shoIMM函数在这里
private void showIMM() {
mFace.setTag(1);
showOrHideIMM();
}
第一句话是个表情的panel添加一个tag (tag是一个object类型 ,可以理解为个view的附加信息)
现在需要显示的是输入法,mFace.getTag!=null于是会显示输入法隐藏表情panel
private void showOrHideIMM() {
if(mFace.getTag() == null){
//隐藏软键盘
imm.hideSoftInputFromWindow(mContent.getWindowToken(), 0);
//显示表情
showFace();
}else{
//显示软键盘
imm.showSoftInput(mContent, 0);
//隐藏表情
hideFace();
}
}
imm在activity启动的时候定义的
//软键盘管理类
imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
在showFace和hideFace的时候,处理设置panel的可见与否还会设置是face的tag 以标示face的可见状态
private void showFace() {
mFace.setImageResource(R.drawable.widget_bar_keyboard);
mFace.setTag(1);
mGridView.setVisibility(View.VISIBLE);
}
private void hideFace() {
mFace.setImageResource(R.drawable.widget_bar_face);
mFace.setTag(null);
mGridView.setVisibility(View.GONE);
}
这时候如果在显示表情就显示输入法,如果在显示输入法就显示表情
流程图如下
3.选择图片并处理上传的两张方式 包括拍照和从相册
选择图片分为两种,相机和相册 在函数 imageChooseItem中:
相册选图的实现:
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, "选择图片"),ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD);
相机拍照的实现:
首先是启动相机 作者对一些异常都做了判断:\
//拍照
else if( item == 1 )
{
String savePath = "";
//判断是否挂载了SD卡
String storageState = Environment.getExternalStorageState();
if(storageState.equals(Environment.MEDIA_MOUNTED)){
savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSChina/Camera/";//存放照片的文件夹
File savedir = new File(savePath);
if (!savedir.exists()) {
savedir.mkdirs();
}
}
//没有挂载SD卡,无法保存文件
if(StringUtils.isEmpty(savePath)){
UIHelper.ToastMessage(TweetPub.this, "无法保存照片,请检查SD卡是否挂载");
return;
}
String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String fileName = "osc_" + timeStamp + ".jpg";//照片命名
File out = new File(savePath, fileName);
Uri uri = Uri.fromFile(out);
theLarge = savePath + fileName;//该照片的绝对路径
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA);
}
在一个新的线程 对得到的图片 如果是从相册得到的 会检查一下可以从相册数据库中拿到缩略图吗,如果拿不到就是用imageUtil 裁剪为缩略图:
if(requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYSDCARD)
{
if(data == null) return;
Uri thisUri = data.getData();
String thePath = ImageUtils.getAbsolutePathFromNoStandardUri(thisUri);
//如果是标准Uri
if(StringUtils.isEmpty(thePath))
{
theLarge = ImageUtils.getAbsoluteImagePath(TweetPub.this,thisUri);
}
else
{
theLarge = thePath;
}
String attFormat = FileUtils.getFileFormat(theLarge);
if(!"photo".equals(MediaUtils.getContentType(attFormat)))
{
Toast.makeText(TweetPub.this, getString(R.string.choose_image), Toast.LENGTH_SHORT).show();
return;
}
//获取图片缩略图 只有Android2.1以上版本支持
if(AppContext.isMethodsCompat(android.os.Build.VERSION_CODES.ECLAIR_MR1)){
String imgName = FileUtils.getFileName(theLarge);
bitmap = ImageUtils.loadImgThumbnail(TweetPub.this, imgName, MediaStore.Images.Thumbnails.MICRO_KIND);
}
if(bitmap == null && !StringUtils.isEmpty(theLarge))
{
bitmap = ImageUtils.loadImgThumbnail(theLarge, 100, 100);
}
}
如果是来自相机的图片,就直接生成缩略图
//拍摄图片
else if(requestCode == ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA)
{
if(bitmap == null && !StringUtils.isEmpty(theLarge))
{
bitmap = ImageUtils.loadImgThumbnail(theLarge, 100, 100);
}
}
最后就把拿到的图片压缩成800 宽度的进行 等完成了就通知UI把拿到的图片显示到编辑界面上:用户就可以发送了~
if(bitmap!=null)
{
//存放照片的文件夹
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/OSChina/Camera/";
File savedir = new File(savePath);
if (!savedir.exists()) {
savedir.mkdirs();
}
String largeFileName = FileUtils.getFileName(theLarge);
String largeFilePath = savePath + largeFileName;
//判断是否已存在缩略图
if(largeFileName.startsWith("thumb_") && new File(largeFilePath).exists())
{
theThumbnail = largeFilePath;
imgFile = new File(theThumbnail);
}
else
{
//生成上传的800宽度图片
String thumbFileName = "thumb_" + largeFileName;
theThumbnail = savePath + thumbFileName;
if(new File(theThumbnail).exists())
{
imgFile = new File(theThumbnail);
}
else
{
try {
//压缩上传的图片
ImageUtils.createImageThumbnail(TweetPub.this, theLarge, theThumbnail, 800, 80);
imgFile = new File(theThumbnail);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//保存动弹临时图片
((AppContext)getApplication()).setProperty(tempTweetImageKey, theThumbnail);
Message msg = new Message();
msg.what = 1;
msg.obj = bitmap;
handler.sendMessage(msg);
}
};