使用的第三方控件,主要关注如下一些文件
- RoundedDrawable
- RoundedImageView
- RoundedTransformationBuilder
- res目录下的anim、color以及values下的attrs
布局文件代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res/com.soulrelay.uploadpic" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:background="@color/f5f5f5">
<com.soulrelay.uploadpic.view.RoundedImageView android:id="@+id/imageCover" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginLeft="50dp" android:layout_centerVertical="true" android:scaleType="center" android:src="@drawable/default_cover_img" app:border_color="@color/border" app:border_width="1dip" app:corner_radius="10dp" app:mutate_background="true" app:oval="false" />
<TextView android:id="@+id/add_cover_txt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:layout_toRightOf="@id/imageCover" android:text="添加封面" android:textColor="@color/_3e363d" android:textSize="15sp" />
</RelativeLayout>
关注如下文件:
- CoverSelelctPopupWindow
- cover_select_pop_layout.xml
public class CoverSelelctPopupWindow extends PopupWindow {
private Button albumBtn, photoGraphBtn,cancelBtn;
private View mMenuView;
public CoverSelelctPopupWindow(Activity context, OnClickListener itemsOnClick) {
super(context);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mMenuView = inflater.inflate(R.layout.cover_select_pop_layout, null);
albumBtn = (Button) mMenuView.findViewById(R.id.btn_album);
photoGraphBtn = (Button) mMenuView.findViewById(R.id.btn_photo_graph);
//startRecordBtn = (Button) mMenuView.findViewById(R.id.btn_upload_record);
cancelBtn = (Button) mMenuView.findViewById(R.id.btn_cancel_join);
// 设置按钮监听
albumBtn.setOnClickListener(itemsOnClick);
photoGraphBtn.setOnClickListener(itemsOnClick);
// 设置SelectPicPopupWindow的View
this.setContentView(mMenuView);
// 设置SelectPicPopupWindow弹出窗体的宽
this.setWidth(LayoutParams.FILL_PARENT);
// 设置SelectPicPopupWindow弹出窗体的高
this.setHeight(LayoutParams.WRAP_CONTENT);
// 设置SelectPicPopupWindow弹出窗体可点击
this.setFocusable(true);
// 设置SelectPicPopupWindow弹出窗体动画效果
this.setAnimationStyle(R.style.AnimBottom);
// 实例化一个ColorDrawable颜色为半透明
ColorDrawable dw = new ColorDrawable(0x00FFFFFF);
// 设置SelectPicPopupWindow弹出窗体的背景
this.setBackgroundDrawable(dw);
// mMenuView添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框
mMenuView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int height = mMenuView.findViewById(R.id.pop_layout).getTop();
int y = (int) event.getY();
if (event.getAction() == MotionEvent.ACTION_UP) {
if (y < height) {
dismiss();
}
}
return true;
}
});
cancelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="vertical" >
<LinearLayout android:id="@+id/pop_layout" android:layout_width="fill_parent" android:layout_height="175dp" android:background="@color/f33e363d" android:gravity="center_horizontal" android:orientation="vertical" >
<Button android:id="@+id/btn_album" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:layout_marginTop="16dip" android:textSize="14sp" android:background="@drawable/btn_report_selector" android:text="@string/user_info_photo_album" android:textColor="@color/_3e363d" />
<Button android:id="@+id/btn_photo_graph" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:layout_marginTop="8dip" android:textSize="14sp" android:background="@drawable/btn_report_selector" android:text="@string/user_info_photo_camera" android:textColor="@color/_3e363d" />
<Button android:id="@+id/btn_cancel_join" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="16dip" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:textSize="14sp" android:background="@drawable/btn_report_selector" android:text="@string/join_cancel_txt" android:textColor="@color/_6f6a6f" />
</LinearLayout>
</RelativeLayout>
public class MainActivity extends Activity implements android.view.View.OnClickListener {
private RoundedImageView imgCover;
private TextView addCover;
private CoverSelelctPopupWindow coverSelelctPopupWindow;
public static final int ACTIVITY_ALBUM_REQUESTCODE = 2000;
public static final int ACTIVITY_CAMERA_REQUESTCODE = 2001;
public static final int ACTIVITY_MODIFY_PHOTO_REQUESTCODE = 2002;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
imgCover = (RoundedImageView) this.findViewById(R.id.imageCover);
addCover = (TextView) this.findViewById(R.id.add_cover_txt);
imgCover.setOnClickListener(this);
addCover.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageCover:
case R.id.add_cover_txt:
coverSelelctPopupWindow = new CoverSelelctPopupWindow(this, itemsOnClick);
coverSelelctPopupWindow.showAtLocation(findViewById(R.id.add_cover_txt), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); //设置layout在PopupWindow中显示的位置
break;
default:
break;
}
}
// 为弹出窗口实现监听类
private OnClickListener itemsOnClick = new OnClickListener() {
public void onClick(View v) {
coverSelelctPopupWindow.dismiss();
if (CommonUtils.isFastDoubleClick()) {
return;
}
switch (v.getId()) {
case R.id.btn_album:
Intent i = new Intent(Intent.ACTION_PICK, null);// 调用android的图库
i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(i, ACTIVITY_ALBUM_REQUESTCODE);
break;
case R.id.btn_photo_graph:
if (CommonUtils.isExistCamera(MainActivity.this)) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 调用android自带的照相机
Uri imageUri = Uri.fromFile(FileUtil.getHeadPhotoFileRaw());
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
startActivityForResult(intent, ACTIVITY_CAMERA_REQUESTCODE);
} else {
Toast.makeText(MainActivity.this,
getResources().getString(R.string.user_no_camera),
Toast.LENGTH_SHORT).show();
}
break;
}
}
};
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case ACTIVITY_ALBUM_REQUESTCODE:
if (resultCode == Activity.RESULT_OK) {
if(data.getData() == null){
ToastUtils.toast(this, getString(R.string.pic_not_valid));
return;
}
CommonUtils.cutPhoto(this, data.getData(), true);
}
break;
case ACTIVITY_CAMERA_REQUESTCODE:
if (resultCode == Activity.RESULT_OK) {
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = 2;
int degree = FileUtil.readPictureDegree(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
Bitmap cameraBitmap = BitmapFactory.decodeFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW, bitmapOptions);
cameraBitmap = FileUtil.rotaingImageView(degree, cameraBitmap);
FileUtil.saveCutBitmapForCache(this,cameraBitmap);
CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);
}
break;
case ACTIVITY_MODIFY_PHOTO_REQUESTCODE:
// Bundle bundle = data.getExtras();
// if (bundle != null) {
// Bitmap bitmap = bundle.getParcelable("data");
// if (bitmap == null) {
// return;
// }
// headImg.setImageBitmap(bitmap);
// }
String coverPath = FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_TEMP;
Bitmap bitmap = BitmapFactory.decodeFile(coverPath);
imgCover.setImageBitmap(bitmap);
//接下来是完成上传功能
/* HttpUtil.uploadCover(this, UrlContainer.UP_LIVE_COVER + "?uid=" + LoginUtils.getInstance(this), coverPath, this);*/
//成功之后删除临时图片
FileUtil.deleteTempAndRaw();
break;
}
}
}
过程中发现,如果拍照获取图片的存储路径与裁切后存储的路径一致的话会出现问题,所以分别设置了两个路径,请参考
- FileUtil
相关代码
public class FileUtil {
private static final String TAG = "FileUtil";
// 用户头像保存位置
private final static String HEADPHOTO_PATH = "/Android/data/com.soulrelay.uploadpic/";
// 剪切头像时临时保存头像名字,完成或取消时删除
public final static String HEADPHOTO_NAME_TEMP = "user_photo_temp.jpg";
//拍照临时存取图片
public final static String HEADPHOTO_NAME_RAW = "user_photo_raw.jpg";
// 剪切壁纸图片
private final static String WALLPAPER = "wallpaper.jpg";
public static String getCropPath(String path) {
String storageState = Environment.getExternalStorageState();
if (Environment.MEDIA_REMOVED.equals(storageState)) {
return null;
}
String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + HEADPHOTO_PATH + "cache" + File.separator;
String s = MD5.Md5Encode(path)+".jpg";
return dirPath + s;
}
/** * 用户头像保存路径 */
public static String getHeadPhotoDir() {
String storageState = Environment.getExternalStorageState();
if (Environment.MEDIA_REMOVED.equals(storageState)) {
return null;
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + HEADPHOTO_PATH;
SDCardUtil.mkdirs(path);
return path;
}
/** * 剪切头像时临时保存头像名字,完成或取消时删除 */
public static File getHeadPhotoFileTemp() {
File file = new File(getHeadPhotoDir() + HEADPHOTO_NAME_TEMP);
return file;
}
/** * 剪切头像时临时保存头像名字,完成或取消时删除(用于拍照时存储原始图片) */
public static File getHeadPhotoFileRaw() {
File file = new File(getHeadPhotoDir() + HEADPHOTO_NAME_RAW);
return file;
}
/** * 获取剪切壁纸图片 */
public static File getWallPaperFile() {
File file = new File(getHeadPhotoDir() + WALLPAPER);
return file;
}
public static void saveCutBitmapForCache(Context context, Bitmap bitmap) {
File file = new File(getHeadPhotoDir() + /*File.separator +*/ HEADPHOTO_NAME_RAW);
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/** * 读取图片属性:旋转的角度 * @param path 图片绝对路径 * @return degree旋转的角度 */
public static int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return degree;
}
/** * 旋转图片 * @param angle * @param bitmap * @return Bitmap */
public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
//旋转图片 动作
Matrix matrix = new Matrix();;
matrix.postRotate(angle);
System.out.println("angle2=" + angle);
// 创建新的图片
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return resizedBitmap;
}
/** * Delete the file/dir from the local disk * */
public static boolean deleteFile(String filePath) {
if (TextUtils.isEmpty(filePath)) {
return false;
}
File file = new File(filePath);
if (!file.exists()) {
Log.w(TAG, "the file is not exist while delete the file");
return false;
}
return deleteDir(file);
}
/** * Delete the file from the local disk * * @param dir */
private static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
if (children != null) {
// 递归删除目录中的子目录下
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
}
if (!dir.canRead() || !dir.canWrite()) {
Log.w(TAG, "has no permission to can or write while delete the file");
return false;
}
// 目录此时为空,可以删除
return dir.delete();
}
/** * 删除临时文件(拍照的原始图片以及临时文件) * @param path */
public static void deleteTempAndRaw() {
deleteFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_TEMP);
deleteFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
}
}
case ACTIVITY_CAMERA_REQUESTCODE:
if (resultCode == Activity.RESULT_OK) {
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = 2;
int degree = FileUtil.readPictureDegree(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
Bitmap cameraBitmap = BitmapFactory.decodeFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW, bitmapOptions);
cameraBitmap = FileUtil.rotaingImageView(degree, cameraBitmap);
FileUtil.saveCutBitmapForCache(this,cameraBitmap);
CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);
}
break;
如果不存在图片角度的问题可以直接调用(我测试的时候发现:型号相同,系统版本相同的手机上也有可能存在角度不统一的问题,如果有更好的处理方法,欢迎指教!)
CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);
可以根据服务器接口形式,来进行图片上传,我这边上传的格式是
传入两个参数
- uid 用户id
- image 图片二进制数据
case ACTIVITY_MODIFY_PHOTO_REQUESTCODE:
String coverPath = FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_TEMP;
Bitmap bitmap = BitmapFactory.decodeFile(coverPath);
imgCover.setImageBitmap(bitmap);
//接下来是完成上传功能
/* HttpUtil.uploadCover(this, UrlContainer.UP_LIVE_COVER + "?uid=" + LoginUtils.getInstance(this), coverPath, this);*/
//成功之后删除临时图片
FileUtil.deleteTempAndRaw();
大家可以在自己的网络请求中按照如下方式处理,然后根据上传成功和失败的回调做相应的事情
ublic static void uploadCover(final Context context, final String url, final String path,
final UploadLiveCoverListener listener) {
ThreadPoolUtils.execute(new Runnable() {
@Override
public void run() {
// 添加密钥
try {
HttpClient client = new DefaultHttpClient();
MultipartEntity multipartContent = getEntity(context,
new HashMap<String, String>());
FileBody fileBody = new FileBody(new File(path), "image/jpeg", "UTF-8");
multipartContent.addPart("image", fileBody);
String ret = doPost(context, url, multipartContent, client);
JSONObject json = new JSONObject(ret);
int status = json.getInt("status");
if (status == 0) {
JSONObject resultO = json.getJSONObject("result");
String imgUrl = resultO.getString("img_url");
listener.onUploadSuccess(imgUrl);
}else {
listener.onUploadFail(status);
}
deleteTempAndRaw(path);
} catch (Exception e) {
listener.onUploadFail(-1);
}
}
});
}
源代码地址:选我选我选我