Android圖片上傳(頭像裁切+原圖原樣)

先看一下效果圖:

(一)頭像裁切、上傳服務器(效果圖)

一般都是有圓形顯示頭像的,這裏我自定義了一個ImageView,頁面很乾淨但是看着很上檔次吧!

點擊頭像從底部彈出一個對話框,提示用戶頭像來自相機或者相冊,這都是常規流程。

上傳完成後默認的“程序員頭像”換成了萌妹子


\
\
\

(二)普通圖片上傳服務器(效果圖)

模仿QQ空間發動態的佈局隨意捏造一個界面出來

點擊添加圖片從底部彈出一個對話框,提示用戶圖片來自相機或者相冊,這也都是常規流程。

上傳過程中,有可能圖片很大,顯示一個進度圈(其實頭像上傳也有,只是文件小,還沒顯示就上傳完成了)

上傳完成後把剛纔的照片亮出來顯示到按鈕的地方,當然大家根據需要還可以自己擴展(比如長按抖動出現刪除、繼續添加N張等等)。

\
\
\
\

下面簡單鋪一下代碼:

(一)頭像裁切、上傳服務器(代碼)

這裏上邊的按鈕是頭像的點擊事件,彈出底部的頭像選擇框,下邊的按鈕跳到下個頁面,進行原圖上傳。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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;
    }
}
彈出窗綁定一個按鈕事件
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//爲彈出窗口實現監聽類 
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;
        }
    }
};
爲圖像選取返回的接收處理
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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);
}
把圖片顯示出來,然後上傳
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
 * 裁剪圖片方法實現
 * @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;
    }
});</string,></string,></string,></string,></string,></string,>

 

(二)普通圖片上傳服務器(代碼)

直接從這裏開始,和頭像那裏基本沒什麼區別,我把拍照什麼的單獨抽出了方法,思路更清晰
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//爲彈出窗口實現監聽類 
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;
        }
    }
};
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * 拍照獲取圖片
 */
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);
}
處理一下圖片選取的頁面回調
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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);
    }
接下來就是顯示圖片和上傳服務器了,上傳和頭像是同一個流程,只是不進行裁切
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
 * 選擇圖片後,獲取圖片的路徑
 *
 * @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;
    }
});</string,></string,></string,></string,></string,></string,>

歡迎加入技術學習羣:364595326




發佈了10 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章