標籤:
還是那句話,最近項目比較忙拖了很久這篇文章終於完成了!
先看一下:
(一)頭像裁切、上傳伺服器()
一般都是有圓形顯示頭像的,這裡我自訂了一個ImageView,頁面很乾淨但是看著很上檔次吧!
點擊頭像從底部彈出一個對話方塊,提示帳戶圖片來自相機或者相簿,這都是常規流程。
上傳完成後預設的“程式員頭像”換成了萌妹子
(二)普通圖片上傳伺服器()
模仿QQ空間發動態布局隨意捏造一個介面出來
點擊添加圖片從底部彈出一個對話方塊,提示使用者圖片來自相機或者相簿,這也都是常規流程。
上傳過程中,有可能圖片很大,顯示一個進度圈(其實頭像上傳也有,只是檔案小,還沒顯示就上傳完成了)
上傳完成後把剛才的照片亮出來顯示到按鈕的地方,當然大家根據需要還可以自己擴充(比如長按抖動出現刪除、繼續添加N張等等)
下面簡單鋪一下代碼:
(一)頭像裁切、上傳伺服器(代碼)
這裡上邊的按鈕是頭像的點擊事件,彈出底部的頭像選擇框,下邊的按鈕跳到下個頁面,進行原圖上傳。
@Overridepublic 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;}}彈出窗綁定一個按鈕事件
//為快顯視窗實現監聽類 private OnClickListener itemsOnClick = new OnClickListener() {@Overridepublic 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;}}}; 為映像選取返回的接收處理
@Overridepublic 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);}把圖片顯示出來,然後上傳
/** * 裁剪圖片方法實現 * @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() {@Overridepublic 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");// 設定contentTypeconn.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() {@Overridepublic 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;}});
(二)普通圖片上傳伺服器(代碼) 直接從這裡開始,和頭像那裡基本沒什麼區別,我把拍照什麼的單獨抽出了方法,思路更清晰
//為快顯視窗實現監聽類 private OnClickListener itemsOnClick = new OnClickListener() {@Overridepublic 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;}}};
/** * 拍照擷取圖片 */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);}處理一片選取的頁面回調
@Overrideprotected 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);}接下來就是顯示圖片和上傳伺服器了,上傳和頭像是同一個流程,只是不進行裁切
/** * 選擇圖片後,擷取圖片的路徑 * * @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路徑讀出BitmapBitmap 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() {@Overridepublic 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");// 設定contentTypeconn.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() {@Overridepublic 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;}});
最後放上
完整的代碼!大家上傳路徑自己搭建啊!
採集採集
Android圖片上傳(頭像裁切+原圖原樣)