您的位置:首页 > 移动开发 > Android开发

Android 图片上传(头像裁切+原图原样)

2015-07-30 23:01 525 查看
还是那句话,最近项目比较忙

拖了很久这篇文章终于完成了!

先看一下效果图:

(一)头像裁切、上传服务器(效果图)

一般都是有圆形显示头像的,这里我自定义了一个ImageView,页面很干净但是看着很上档次吧!

点击头像从底部弹出一个对话框,提示用户头像来自相机或者相册,这都是常规流程。

上传完成后默认的“程序员头像”换成了萌妹子







(二)普通图片上传服务器(效果图)

模仿QQ空间发动态的布局随意捏造一个界面出来

点击添加图片从底部弹出一个对话框,提示用户图片来自相机或者相册,这也都是常规流程。

上传过程中,有可能图片很大,显示一个进度圈(其实头像上传也有,只是文件小,还没显示就上传完成了



上传完成后把刚才的照片亮出来显示到按钮的地方,当然大家根据需要还可以自己扩展(比如长按抖动出现删除、继续添加N张等等)









下面简单铺一下代码:

(一)头像裁切、上传服务器(代码)

这里上边的按钮是头像的点击事件,弹出底部的头像选择框,下边的按钮跳到下个页面,进行原图上传。

[java] view
plaincopy





@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.avatarImg:// 更换头像点击事件

menuWindow = new SelectPicPopupWindow(mContext, itemsOnClick);

menuWindow.showAtLocation(findViewById(R.id.mainLayout),

Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);

break;

case R.id.loginBtn://登录按钮跳转事件

startActivity(new Intent(mContext, UploadActivity.class));

break;



default:

break;

}

}

弹出窗绑定一个按钮事件。

[java] view
plaincopy





//为弹出窗口实现监听类

private OnClickListener itemsOnClick = new OnClickListener() {

@Override

public void onClick(View v) {

menuWindow.dismiss();

switch (v.getId()) {

// 拍照

case R.id.takePhotoBtn:

Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

//下面这句指定调用相机拍照后的照片存储的路径

takeIntent.putExtra(MediaStore.EXTRA_OUTPUT,

Uri.fromFile(new File(Environment.getExternalStorageDirectory(), IMAGE_FILE_NAME)));

startActivityForResult(takeIntent, REQUESTCODE_TAKE);

break;

// 相册选择图片

case R.id.pickPhotoBtn:

Intent pickIntent = new Intent(Intent.ACTION_PICK, null);

// 如果朋友们要限制上传到服务器的图片类型时可以直接写如:"image/jpeg 、 image/png等的类型"

pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");

startActivityForResult(pickIntent, REQUESTCODE_PICK);

break;

default:

break;

}

}

};

为图像选取返回的接收处理。

[java] view
plaincopy





@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {



switch (requestCode) {

case REQUESTCODE_PICK:// 直接从相册获取

try {

startPhotoZoom(data.getData());

} catch (NullPointerException e) {

e.printStackTrace();// 用户点击取消操作

}

break;

case REQUESTCODE_TAKE:// 调用相机拍照

File temp = new File(Environment.getExternalStorageDirectory() + "/" + IMAGE_FILE_NAME);

startPhotoZoom(Uri.fromFile(temp));

break;

case REQUESTCODE_CUTTING:// 取得裁剪后的图片

if (data != null) {

setPicToView(data);

}

break;

}

super.onActivityResult(requestCode, resultCode, data);

}

把图片显示出来,然后上传。

[java] view
plaincopy





/**

* 裁剪图片方法实现

* @param uri

*/

public void startPhotoZoom(Uri uri) {

Intent intent = new Intent("com.android.camera.action.CROP");

intent.setDataAndType(uri, "image/*");

// crop=true是设置在开启的Intent中设置显示的VIEW可裁剪

intent.putExtra("crop", "true");

// aspectX aspectY 是宽高的比例

intent.putExtra("aspectX", 1);

intent.putExtra("aspectY", 1);

// outputX outputY 是裁剪图片宽高

intent.putExtra("outputX", 300);

intent.putExtra("outputY", 300);

intent.putExtra("return-data", true);

startActivityForResult(intent, REQUESTCODE_CUTTING);

}



/**

* 保存裁剪之后的图片数据

* @param picdata

*/

private void setPicToView(Intent picdata) {

Bundle extras = picdata.getExtras();

if (extras != null) {

// 取得SDCard图片路径做显示

Bitmap photo = extras.getParcelable("data");

Drawable drawable = new BitmapDrawable(null, photo);

urlpath = FileUtil.saveFile(mContext, "temphead.jpg", photo);

avatarImg.setImageDrawable(drawable);



// 新线程后台上传服务端

pd = ProgressDialog.show(mContext, null, "正在上传图片,请稍候...");

new Thread(uploadImageRunnable).start();

}

}



/**

* 使用HttpUrlConnection模拟post表单进行文件

* 上传平时很少使用,比较麻烦

* 原理是: 分析文件上传的数据格式,然后根据格式构造相应的发送给服务器的字符串。

*/

Runnable uploadImageRunnable = new Runnable() {

@Override

public void run() {



if(TextUtils.isEmpty(imgUrl)){

Toast.makeText(mContext, "还没有设置上传服务器的路径!", Toast.LENGTH_SHORT).show();

return;

}



Map<String, String> textParams = new HashMap<String, String>();

Map<String, File> fileparams = new HashMap<String, File>();



try {

// 创建一个URL对象

URL url = new URL(imgUrl);

textParams = new HashMap<String, String>();

fileparams = new HashMap<String, File>();

// 要上传的图片文件

File file = new File(urlpath);

fileparams.put("image", file);

// 利用HttpURLConnection对象从网络中获取网页数据

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

// 设置连接超时(记得设置连接超时,如果网络不好,Android系统在超过默认时间会收回资源中断操作)

conn.setConnectTimeout(5000);

// 设置允许输出(发送POST请求必须设置允许输出)

conn.setDoOutput(true);

// 设置使用POST的方式发送

conn.setRequestMethod("POST");

// 设置不使用缓存(容易出现问题)

conn.setUseCaches(false);

conn.setRequestProperty("Charset", "UTF-8");//设置编码

// 在开始用HttpURLConnection对象的setRequestProperty()设置,就是生成HTML文件头

conn.setRequestProperty("ser-Agent", "Fiddler");

// 设置contentType

conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + NetUtil.BOUNDARY);

OutputStream os = conn.getOutputStream();

DataOutputStream ds = new DataOutputStream(os);

NetUtil.writeStringParams(textParams, ds);

NetUtil.writeFileParams(fileparams, ds);

NetUtil.paramsEnd(ds);

// 对文件流操作完,要记得及时关闭

os.close();

// 服务器返回的响应吗

int code = conn.getResponseCode(); // 从Internet获取网页,发送请求,将网页以流的形式读回来

// 对响应码进行判断

if (code == 200) {// 返回的响应码200,是成功

// 得到网络返回的输入流

InputStream is = conn.getInputStream();

resultStr = NetUtil.readString(is);

} else {

Toast.makeText(mContext, "请求URL失败!", Toast.LENGTH_SHORT).show();

}

} catch (Exception e) {

e.printStackTrace();

}

handler.sendEmptyMessage(0);// 执行耗时的方法之后发送消给handler

}

};



Handler handler = new Handler(new Handler.Callback() {



@Override

public boolean handleMessage(Message msg) {

switch (msg.what) {

case 0:

pd.dismiss();



try {

// 返回数据示例,根据需求和后台数据灵活处理

// {"status":"1","statusMessage":"上传成功","imageUrl":"http://120.24.219.49/726287_temphead.jpg"}

JSONObject jsonObject = new JSONObject(resultStr);



// 服务端以字符串“1”作为操作成功标记

if (jsonObject.optString("status").equals("1")) {

BitmapFactory.Options option = new BitmapFactory.Options();

// 压缩图片:表示缩略图大小为原始图片大小的几分之一,1为原图,3为三分之一

option.inSampleSize = 1;



// 服务端返回的JsonObject对象中提取到图片的网络URL路径

String imageUrl = jsonObject.optString("imageUrl");

Toast.makeText(mContext, imageUrl, Toast.LENGTH_SHORT).show();

}else{

Toast.makeText(mContext, jsonObject.optString("statusMessage"), Toast.LENGTH_SHORT).show();

}



} catch (JSONException e) {

e.printStackTrace();

}



break;



default:

break;

}

return false;

}

});

(二)普通图片上传服务器(代码)

直接从这里开始,和头像那里基本没什么区别,我把拍照什么的单独抽出了方法,思路更清晰。

[java] view
plaincopy





//为弹出窗口实现监听类

private OnClickListener itemsOnClick = new OnClickListener() {

@Override

public void onClick(View v) {

// 隐藏弹出窗口

menuWindow.dismiss();



switch (v.getId()) {

case R.id.takePhotoBtn:// 拍照

takePhoto();

break;

case R.id.pickPhotoBtn:// 相册选择图片

pickPhoto();

break;

case R.id.cancelBtn:// 取消

break;

default:

break;

}

}

};

[java] view
plaincopy





/**

* 拍照获取图片

*/

private void takePhoto() {

// 执行拍照前,应该先判断SD卡是否存在

String SDState = Environment.getExternalStorageState();

if (SDState.equals(Environment.MEDIA_MOUNTED)) {



Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

/***

* 需要说明一下,以下操作使用照相机拍照,拍照后的图片会存放在相册中的

* 这里使用的这种方式有一个好处就是获取的图片是拍照后的原图

* 如果不使用ContentValues存放照片路径的话,拍照后获取的图片为缩略图不清晰

*/

ContentValues values = new ContentValues();

photoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, photoUri);

startActivityForResult(intent, SELECT_PIC_BY_TACK_PHOTO);

} else {

Toast.makeText(this, "内存卡不存在", Toast.LENGTH_LONG).show();

}

}



/***

* 从相册中取图片

*/

private void pickPhoto() {

Intent intent = new Intent();

// 如果要限制上传到服务器的图片类型时可以直接写如:"image/jpeg 、 image/png等的类型"

intent.setType("image/*");

intent.setAction(Intent.ACTION_GET_CONTENT);

startActivityForResult(intent, SELECT_PIC_BY_PICK_PHOTO);

}

处理一下图片选取的页面回调。

[java] view
plaincopy





@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

// 点击取消按钮

if(resultCode == RESULT_CANCELED){

return;

}



// 可以使用同一个方法,这里分开写为了防止以后扩展不同的需求

switch (requestCode) {

case SELECT_PIC_BY_PICK_PHOTO:// 如果是直接从相册获取

doPhoto(requestCode, data);

break;

case SELECT_PIC_BY_TACK_PHOTO:// 如果是调用相机拍照时

doPhoto(requestCode, data);

break;

}

super.onActivityResult(requestCode, resultCode, data);

}

接下来就是显示图片和上传服务器了,上传和头像是同一个流程,只是不进行裁切。

[java] view
plaincopy





/**

* 选择图片后,获取图片的路径

*

* @param requestCode

* @param data

*/

private void doPhoto(int requestCode, Intent data) {



// 从相册取图片,有些手机有异常情况,请注意

if (requestCode == SELECT_PIC_BY_PICK_PHOTO) {

if (data == null) {

Toast.makeText(this, "选择图片文件出错", Toast.LENGTH_LONG).show();

return;

}

photoUri = data.getData();

if (photoUri == null) {

Toast.makeText(this, "选择图片文件出错", Toast.LENGTH_LONG).show();

return;

}

}



String[] pojo = { MediaColumns.DATA };

// The method managedQuery() from the type Activity is deprecated

//Cursor cursor = managedQuery(photoUri, pojo, null, null, null);

Cursor cursor = mContext.getContentResolver().query(photoUri, pojo, null, null, null);

if (cursor != null) {

int columnIndex = cursor.getColumnIndexOrThrow(pojo[0]);

cursor.moveToFirst();

picPath = cursor.getString(columnIndex);



// 4.0以上的版本会自动关闭 (4.0--14;; 4.0.3--15)

if (Integer.parseInt(Build.VERSION.SDK) < 14) {

cursor.close();

}

}



// 如果图片符合要求将其上传到服务器

if (picPath != null && ( picPath.endsWith(".png") ||

picPath.endsWith(".PNG") ||

picPath.endsWith(".jpg") ||

picPath.endsWith(".JPG"))) {





BitmapFactory.Options option = new BitmapFactory.Options();

// 压缩图片:表示缩略图大小为原始图片大小的几分之一,1为原图

option.inSampleSize = 1;

// 根据图片的SDCard路径读出Bitmap

Bitmap bm = BitmapFactory.decodeFile(picPath, option);

// 显示在图片控件上

picImg.setImageBitmap(bm);



pd = ProgressDialog.show(mContext, null, "正在上传图片,请稍候...");

new Thread(uploadImageRunnable).start();

} else {

Toast.makeText(this, "选择图片文件不正确", Toast.LENGTH_LONG).show();

}



}



/**

* 使用HttpUrlConnection模拟post表单进行文件

* 上传平时很少使用,比较麻烦

* 原理是: 分析文件上传的数据格式,然后根据格式构造相应的发送给服务器的字符串。

*/

Runnable uploadImageRunnable = new Runnable() {

@Override

public void run() {



if(TextUtils.isEmpty(imgUrl)){

Toast.makeText(mContext, "还没有设置上传服务器的路径!", Toast.LENGTH_SHORT).show();

return;

}



Map<String, String> textParams = new HashMap<String, String>();

Map<String, File> fileparams = new HashMap<String, File>();



try {

// 创建一个URL对象

URL url = new URL(imgUrl);

textParams = new HashMap<String, String>();

fileparams = new HashMap<String, File>();

// 要上传的图片文件

File file = new File(picPath);

fileparams.put("image", file);

// 利用HttpURLConnection对象从网络中获取网页数据

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

// 设置连接超时(记得设置连接超时,如果网络不好,Android系统在超过默认时间会收回资源中断操作)

conn.setConnectTimeout(5000);

// 设置允许输出(发送POST请求必须设置允许输出)

conn.setDoOutput(true);

// 设置使用POST的方式发送

conn.setRequestMethod("POST");

// 设置不使用缓存(容易出现问题)

conn.setUseCaches(false);

// 在开始用HttpURLConnection对象的setRequestProperty()设置,就是生成HTML文件头

conn.setRequestProperty("ser-Agent", "Fiddler");

// 设置contentType

conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + NetUtil.BOUNDARY);

OutputStream os = conn.getOutputStream();

DataOutputStream ds = new DataOutputStream(os);

NetUtil.writeStringParams(textParams, ds);

NetUtil.writeFileParams(fileparams, ds);

NetUtil.paramsEnd(ds);

// 对文件流操作完,要记得及时关闭

os.close();

// 服务器返回的响应吗

int code = conn.getResponseCode(); // 从Internet获取网页,发送请求,将网页以流的形式读回来

// 对响应码进行判断

if (code == 200) {// 返回的响应码200,是成功

// 得到网络返回的输入流

InputStream is = conn.getInputStream();

resultStr = NetUtil.readString(is);

} else {

Toast.makeText(mContext, "请求URL失败!", Toast.LENGTH_SHORT).show();

}

} catch (Exception e) {

e.printStackTrace();

}

handler.sendEmptyMessage(0);// 执行耗时的方法之后发送消给handler

}

};



Handler handler = new Handler(new Handler.Callback() {



@Override

public boolean handleMessage(Message msg) {

switch (msg.what) {

case 0:

pd.dismiss();



try {

JSONObject jsonObject = new JSONObject(resultStr);

// 服务端以字符串“1”作为操作成功标记

if (jsonObject.optString("status").equals("1")) {



// 用于拼接发布说说时用到的图片路径

// 服务端返回的JsonObject对象中提取到图片的网络URL路径

String imageUrl = jsonObject.optString("imageUrl");

// 获取缓存中的图片路径

Toast.makeText(mContext, imageUrl, Toast.LENGTH_SHORT).show();

} else {

Toast.makeText(mContext, jsonObject.optString("statusMessage"), Toast.LENGTH_SHORT).show();

}



} catch (JSONException e) {

e.printStackTrace();

}

break;

default:

break;

}

return false;

}

});

最后放上完整的代码!大家上传路径自己搭建啊!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: