衔接上文, 动弹的发送(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属性使用
然后是解决键盘弹出和表情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); }
用户点击表情图标也会触发showOrHideIMM函数,
这时候如果在显示表情就显示输入法,如果在显示输入法就显示表情
流程图如下
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); } };