Android頭像上傳功能的實(shí)現(xiàn)代碼(獲取頭像加剪切)
因?yàn)轫?xiàng)目中需要用到頭像上傳的功能,所以就下個(gè)Ddmo先來(lái)實(shí)現(xiàn)下。
demo我是類(lèi)似仿微信的,在一個(gè)GridView中展示所有的圖片,其中第一個(gè)item可以去照相;獲取到圖片后再進(jìn)行剪切。
圖片的剪切是從網(wǎng)上找的感覺(jué)不錯(cuò)就用,暫時(shí)也沒(méi)有測(cè)試。
獲取圖片可以用:https://github.com/lovetuzitong/MultiImageSelector來(lái)實(shí)現(xiàn)
這里的圓形圖像是用https://github.com/hdodenhof/CircleImageView來(lái)實(shí)現(xiàn)的
Demo寫(xiě)的比較粗糙,效果只是在4.4的手機(jī)和7.0的模擬器跑了一遍,所以可能會(huì)出現(xiàn)問(wèn)題的。
如下是demo的效果圖:
如下是選擇圖片中的代碼
通過(guò)LoaderManager來(lái)獲取到所有的圖片,然后第一個(gè)進(jìn)行拍照的處理
package com.item.demo.photo.activity; import android.Manifest; import android.app.LoaderManager; import android.content.ContentResolver; import android.content.Context; import android.content.CursorLoader; import android.content.Intent; import android.content.Loader; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; import android.support.v4.content.FileProvider; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.GridView; import android.widget.ImageView; import com.item.demo.photo.BuildConfig; import com.item.demo.photo.R; import com.item.demo.photo.adapter.MyPhotoAdapter; import com.item.demo.photo.uilts.Image; import java.io.File; import java.util.ArrayList; import java.util.List; /** * 圖片選擇界面 */ public class MyPhotoActivity extends AppCompatActivity { private static final int REQUEST_CAPTURE = 100; //private static final int REQUEST_PICK = 101; private static final int REQUEST_CROP_PHOTO = 102; public static final int FINSH_RESULT = 104;//截圖后的返回 private static final int LOADER_ID = 0x0100; private LoadCallBack mLoad = new LoadCallBack(); private MyPhotoAdapter mAdapter; private List<Image> images = new ArrayList<>(); //調(diào)用照相機(jī)返回圖片文件 private File tempFile; private static final int MIN_IMAGE_FILE_SIZE = 10 * 1024; // 最小的圖片大小 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_photo); GridView gv_photo = (GridView)findViewById(R.id.gv_photo); ImageView img_back = (ImageView)findViewById(R.id.iv_back); images.add(new Image()); mAdapter = new MyPhotoAdapter(this,images); gv_photo.setAdapter(mAdapter); gv_photo.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { if(i == 0){ //第一個(gè)就去照相 if(hasPermission(new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE})){ gotoCamera(); }else { requestPermission(0x02,new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE}); } }else { //這里點(diǎn)擊獲取到圖片地址然后裁剪 gotoClipActivity(Uri.parse(images.get(i).getPath())); } } }); img_back.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); } @Override protected void onStart() { super.onStart(); if(hasPermission(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE})){ getLoaderManager().initLoader(LOADER_ID,null,mLoad); }else { requestPermission(0x01,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}); } } private class LoadCallBack implements LoaderManager.LoaderCallbacks<Cursor>{ private final String[] IMAGE_PROJECTION = new String[]{ MediaStore.Images.Media._ID,//Id MediaStore.Images.Media.DATA,//圖片路徑 MediaStore.Images.Media.DATE_ADDED//圖片的創(chuàng)建時(shí)間 }; @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { //創(chuàng)建一個(gè)Loader if(id == LOADER_ID){ //如果是我們的ID則進(jìn)行初始化 return new CursorLoader(getBaseContext(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_PROJECTION, null, null, IMAGE_PROJECTION[2] + " DESC"); } return null; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { //當(dāng)Loader加載完成時(shí) List<Image> images = new ArrayList<>(); //判斷是否有數(shù)據(jù) if(data != null){ int count = data.getCount(); if(count > 0){ data.moveToFirst(); // 得到對(duì)應(yīng)的列的Index坐標(biāo) int indexId = data.getColumnIndexOrThrow(IMAGE_PROJECTION[0]); int indexPath = data.getColumnIndexOrThrow(IMAGE_PROJECTION[1]); int indexDate = data.getColumnIndexOrThrow(IMAGE_PROJECTION[2]); do { // 循環(huán)讀取,直到?jīng)]有下一條數(shù)據(jù) int id = data.getInt(indexId); String path = data.getString(indexPath); long dateTime = data.getLong(indexDate); File file = new File(path); if (!file.exists() || file.length() < MIN_IMAGE_FILE_SIZE) { // 如果沒(méi)有圖片,或者圖片大小太小,則跳過(guò) continue; } // 添加一條新的數(shù)據(jù) Image image = new Image(); image.setId(id); image.setPath(path); image.setDate(dateTime); images.add(image); } while (data.moveToNext()); } } updateSource(images); } @Override public void onLoaderReset(Loader<Cursor> loader) { updateSource(null); } } /** * 通知Adapter數(shù)據(jù)更改的方法 * @param images 新的數(shù)據(jù) */ private void updateSource(List<Image> images){ this.images.clear(); this.images.add(new Image()); if(images == null || images.size() == 0) return; this.images.addAll(images); mAdapter.notifyDataSetChanged(); } /** *權(quán)限的返回 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch(requestCode){ case 0x02: if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ gotoCamera(); } break; case 0x01: if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ getLoaderManager().initLoader(LOADER_ID,null,mLoad); } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode){ case REQUEST_CAPTURE://系統(tǒng)相機(jī)返回 if(resultCode == RESULT_OK){ Log.d("jiejie","--------相機(jī)---------" + Uri.fromFile(tempFile).toString()); Log.d("jiejie","--------path----------" + getRealFilePathFromUri(MyPhotoActivity.this,Uri.fromFile(tempFile))); gotoClipActivity(Uri.fromFile(tempFile)); } break; case REQUEST_CROP_PHOTO: if(resultCode == RESULT_OK){ if(data != null){ Uri uri = data.getData(); Log.d("jiejie","-------------" + data.getData().getPath()); String cropImagePath = getRealFilePathFromUri(MyPhotoActivity.this,uri); Log.d("jiejie","------crop--------" + cropImagePath); Intent intent = new Intent(); intent.putExtra("image",cropImagePath); setResult(FINSH_RESULT,intent); MyPhotoActivity.this.finish(); } } break; } } /** * 跳轉(zhuǎn)到系統(tǒng)照相機(jī) */ private void gotoCamera(){ String SDState = Environment.getExternalStorageState(); //判斷SD卡是否存在 if(SDState.equals(Environment.MEDIA_MOUNTED)){ tempFile = new File(checkDirPath(Environment.getExternalStorageDirectory().getPath()+ "/image/"), System.currentTimeMillis() + ".jpg"); //隱式的打開(kāi)調(diào)用系統(tǒng)相冊(cè) Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); //如果是7.0及以上的系統(tǒng)使用FileProvider的方式創(chuàng)建一個(gè)Uri Uri contentUri = FileProvider.getUriForFile(MyPhotoActivity.this, BuildConfig.APPLICATION_ID + ".fileProvider", tempFile); intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri); }else { intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile)); } startActivityForResult(intent,REQUEST_CAPTURE); } } /** * 打開(kāi)截圖的界面 * @param uri */ private void gotoClipActivity(Uri uri){ if(uri == null){ return; } Intent intent = new Intent(this,ClipImageActivity.class); intent.putExtra("type",1); intent.setData(uri); startActivityForResult(intent,REQUEST_CROP_PHOTO); } /** * 檢查文件是否存在 */ private static String checkDirPath(String dirPath) { if (TextUtils.isEmpty(dirPath)) { return ""; } File dir = new File(dirPath); if (!dir.exists()) { dir.mkdirs(); } return dirPath; } /** * 判斷是否有指定的權(quán)限 */ public boolean hasPermission(String... permissions) { for (String permisson : permissions) { if (ContextCompat.checkSelfPermission(this, permisson) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } /** * 申請(qǐng)指定的權(quán)限. */ public void requestPermission(int code, String... permissions) { if (Build.VERSION.SDK_INT >= 23) { requestPermissions(permissions, code); } } /** * 根據(jù)Uri返回文件絕對(duì)路徑 * 兼容了file:///開(kāi)頭的 和 content://開(kāi)頭的情況 */ public static String getRealFilePathFromUri(final Context context, final Uri uri) { if (null == uri) return null; final String scheme = uri.getScheme(); String data = null; if (scheme == null) data = uri.getPath(); else if (ContentResolver.SCHEME_FILE.equals(scheme)) { data = uri.getPath(); } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) { Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null); if (null != cursor) { if (cursor.moveToFirst()) { int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); if (index > -1) { data = cursor.getString(index); } } cursor.close(); } } return data; } }
其中處理動(dòng)態(tài)的權(quán)限還需要添加7.0的照相處理
在清單文件中加如下配置:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.item.demo.photo.fileProvider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
圖片的剪切
package com.item.demo.photo.activity; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.item.demo.photo.R; import com.item.demo.photo.view.ClipViewLayout; import java.io.File; import java.io.IOException; import java.io.OutputStream; /** * 圖片剪切 */ public class ClipImageActivity extends AppCompatActivity implements View.OnClickListener { private ClipViewLayout clipViewLayout1; private ClipViewLayout clipViewLayout2; private ImageView back; private TextView tv_ok; //類(lèi)別 1:圓形 2:方形 private int type; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_clip_image); type = getIntent().getIntExtra("type",1); initView(); } private void initView() { clipViewLayout1 = (ClipViewLayout)findViewById(R.id.clipViewLayout1); clipViewLayout2 = (ClipViewLayout)findViewById(R.id.clipViewLayout2); back = (ImageView)findViewById(R.id.iv_back); tv_ok = (TextView)findViewById(R.id.tv_ok); back.setOnClickListener(this); tv_ok.setOnClickListener(this); } @Override protected void onResume() { super.onResume(); if(type == 1){ clipViewLayout1.setVisibility(View.VISIBLE); clipViewLayout2.setVisibility(View.GONE); //設(shè)置圖片資源 clipViewLayout1.setImageSrc(getIntent().getData()); }else { clipViewLayout2.setVisibility(View.VISIBLE); clipViewLayout1.setVisibility(View.GONE); clipViewLayout2.setImageSrc(getIntent().getData()); } } @Override public void onClick(View view) { switch (view.getId()){ case R.id.iv_back: finish(); break; case R.id.tv_ok: generateUriAndReturn(); break; } } /** * 生成Uri并且通過(guò)setResult返回給打開(kāi)的Activity */ private void generateUriAndReturn() { //調(diào)用返回剪切圖 Bitmap zoomedCropBitmap; if (type == 1) { zoomedCropBitmap = clipViewLayout1.clip(); } else { zoomedCropBitmap = clipViewLayout2.clip(); } if (zoomedCropBitmap == null) { Log.e("android", "zoomedCropBitmap == null"); return; } Uri mSaveUri = Uri.fromFile(new File(getCacheDir(), "cropped_" + System.currentTimeMillis() + ".jpg")); if (mSaveUri != null) { OutputStream outputStream = null; try { outputStream = getContentResolver().openOutputStream(mSaveUri); if (outputStream != null) { zoomedCropBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); } } catch (IOException ex) { Log.e("android", "Cannot open file: " + mSaveUri, ex); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } Intent intent = new Intent(); intent.setData(mSaveUri); setResult(RESULT_OK, intent); finish(); } } }
總結(jié)
以上所述是小編給大家介紹的Android頭像上傳功能的實(shí)現(xiàn)代碼(獲取頭像加剪切),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Android利用HorizontalScrollView仿ViewPager設(shè)計(jì)簡(jiǎn)單相冊(cè)
這篇文章主要介紹了Android利用HorizontalScrollView仿ViewPager設(shè)計(jì)簡(jiǎn)單相冊(cè)的相關(guān)資料,需要的朋友可以參考下2016-05-05Android仿微信實(shí)現(xiàn)評(píng)論功能
這篇文章主要為大家詳細(xì)介紹了Android仿微信實(shí)現(xiàn)評(píng)論功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11Android 圖片特效如何實(shí)現(xiàn)及總結(jié)
這篇文章主要介紹了Android 圖形特效如何實(shí)現(xiàn)及總結(jié)的相關(guān)資料,這里對(duì)Android圖像特效的實(shí)現(xiàn)比如:旋轉(zhuǎn),放大,縮小,傾斜等,需要的朋友可以參考下2016-12-12android實(shí)現(xiàn)icon動(dòng)態(tài)旋轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)icon動(dòng)態(tài)旋轉(zhuǎn)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07詳解如何實(shí)現(xiàn)一個(gè)Kotlin函數(shù)類(lèi)型
這篇文章主要為大家詳細(xì)介紹了如何實(shí)現(xiàn)一個(gè)Kotlin函數(shù)類(lèi)型,文中的實(shí)現(xiàn)方法講解詳細(xì),具有一定的借鑒價(jià)值,需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-10-10Android開(kāi)發(fā)之SeekBar基本使用及各種美觀樣式示例
這篇文章主要介紹了Android開(kāi)發(fā)之SeekBar基本使用及各種美觀樣式,結(jié)合實(shí)例形式分析了Android SeekBar控件的功能及樣式改變相關(guān)操作技巧,需要的朋友可以參考下2019-03-03Android自定義加載loading view動(dòng)畫(huà)組件
這篇文章主要為大家詳細(xì)介紹了Android自定義加載loading view動(dòng)畫(huà)組件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08Android初學(xué)者必須知道的10個(gè)技術(shù)
本篇內(nèi)容給大家整理10個(gè)作為Android初學(xué)者必須要了解和會(huì)用的技術(shù)以及詳細(xì)代碼分析,需要的朋友收藏下慢慢學(xué)習(xí)吧。2017-12-12Android畫(huà)板開(kāi)發(fā)之添加文本文字
這篇文章主要為大家詳細(xì)介紹了Android畫(huà)板開(kāi)發(fā)之添加文本文字功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12