在android平台实现视频中的三国志9头像替换的替换,用什么技术?

78477人阅读
Android(13)
& & & & 最近在做一个从图库选择图片或拍照,然后裁剪的功能.本来是没问题的,一直在用
Intent intent=new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);的方式来做,是调用系统图库来做,但是发现如果有图片是同步到google相册的话,图库里面能看到一个auto backup的目录,点进去选图片的话是无法获取到图片的路径的.因为那些图片根本就不存在于手机上.然后看到无论是百度贴吧,Instagram,或者还有些会选取图片做修改的app,都是用一个很漂亮的图片选择器(4.4以上,4.3的还是用系统旧的图库).
而这个图片选择器可以屏蔽掉那个auto
backup的目录.所以就开始打算用这个图片选择器来选图片了.
这个方法就是
Intent intent=new Intent(Intent.ACTION_GET_CONTENT);//ACTION_OPEN_DOCUMENT
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(&image/jpeg&);
if(android.os.Build.VERSION.SDK_INT&=android.os.Build.VERSION_CODES.KITKAT){
startActivityForResult(intent, SELECT_PIC_KITKAT);
startActivityForResult(intent, SELECT_PIC);
为什么要分开不同版本呢?其实在4.3或以下可以直接用ACTION_GET_CONTENT的,在4.4或以上,官方建议用ACTION_OPEN_DOCUMENT,但其实都不算太大区别,区别是他们返回的Uri,那个才叫大区别.这就是困扰了我一整天的问题所在了.
4.3或以下,选了图片之后,根据Uri来做处理,很多帖子都有了,我就不详细说了.主要是4.4,如果使用上面pick的原生方法来选图,返回的uri还是正常的,但如果用ACTION_GET_CONTENT的方法,返回的uri跟4.3是完全不一样的,4.3返回的是带文件路径的,而4.4返回的却是content://com.android.providers.media.documents/document/image:3951这样的,没有路径,只有图片编号的uri.这就导致接下来无法根据图片路径来裁剪的步骤了.
还好找了很多方法,包括加权限啊什么的,中间还试过用一些方法,自己的app没崩溃,倒是让系统图库崩溃了,引发了java.lang.SecurityException.
Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{437b5d88 9494:com.google.android.gallery3d/u0a20} (pid=9494, uid=10020) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS
看来4.4的系统还是有些bug.重点来了,4.4得到的uri,需要以下方法来获取文件的路径
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT &= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(&:&);
final String type = split[0];
if (&primary&.equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + &/& + split[1];
// TODO handle non-primary volumes
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse(&content://downloads/public_downloads&), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(&:&);
final String type = split[0];
Uri contentUri =
if (&image&.equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if (&video&.equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if (&audio&.equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
final String selection = &_id=?&;
final String[] selectionArgs = new String[] {
return getDataColumn(context, contentUri, selection, selectionArgs);
// MediaStore (and general)
else if (&content&.equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
else if (&file&.equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor =
final String column = &_data&;
final String[] projection = {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
} finally {
if (cursor != null)
cursor.close();
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
public static boolean isExternalStorageDocument(Uri uri) {
return &com.android.externalstorage.documents&.equals(uri.getAuthority());
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
public static boolean isDownloadsDocument(Uri uri) {
return &com.android.providers.downloads.documents&.equals(uri.getAuthority());
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
public static boolean isMediaDocument(Uri uri) {
return &com.android.providers.media.documents&.equals(uri.getAuthority());
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
public static boolean isGooglePhotosUri(Uri uri) {
return &com.google.android.apps.photos.content&.equals(uri.getAuthority());
这样,就可以在4.4上用漂亮的图片选择器,选到我们想要的文件,又不会出问题了.
昨天发现了个bug,如果在4.4上面不用&图片&来选,用&图库&来选,就会无法读取到图片路径,所以只需要加个判断,如果是用旧方式来选,就用旧方式来读,就是如果
DocumentsContract.isDocumentUri(context, uri) 返回false的话,就用旧的方式
public static String selectImage(Context context,Intent data){
Uri selectedImage = data.getData();
Log.e(TAG, selectedImage.toString());
if(selectedImage!=null){
String uriStr=selectedImage.toString();
String path=uriStr.substring(10,uriStr.length());
if(path.startsWith(&com.sec.android.gallery3d&)){
Log.e(TAG, &It's auto backup pic path:&+selectedImage.toString());
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(selectedImage,filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
return pictureP
这样就OK的了
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:106822次
排名:千里之外
原创:13篇
评论:147条
(1)(1)(1)(1)(1)(1)(1)(1)(1)(3)(4)(1)Android应用开发(5)
& & & & & & & & 最近有看到有朋友在讨论QQ头像的裁剪上传是怎么实现的,吼吼,小马也没做过,好奇之下学习下,发现以前项目中有类型的功能,结合官方文档里面的解释,就更好玩了,周末,急急忙忙写的,之前记录在51博客里的,今后会把51是的文章慢慢转移到CSDN,希望能与大家交流学习,让更多的朋友学习使用,也恳请高手能解答小马在代码注释中提出的疑问,不管有没有人回答,小马先谢谢了,一样的,先看下效果图(效果图小马不解释了,直接流水写下去,小马是直接在模拟器里写的,能在真机上使用,因为很简单),再看代码是怎么实现的:
一:主布局界面
二:点击控件触发事件后效果图
三:拍照完之后效果图
四:裁剪界面效果图
五:点击相册后返回的图片效果图
六:裁剪完从相册PICK的保存后的效果图&
下面直接来看下主控制类代码,如下:
package com.xiaoma.piccut.
import java.io.F
import android.app.A
import android.app.AlertD
import android.content.DialogI
import android.content.I
import android.graphics.B
import android.graphics.drawable.BitmapD
import android.graphics.drawable.D
import android.net.U
import android.os.B
import android.os.E
import android.provider.MediaS
import android.view.V
import android.view.View.OnClickL
import android.widget.B
import android.widget.ImageB
import android.widget.ImageV
* @Title: PicCutDemoActivity.java
* @Package com.xiaoma.piccut.demo
* @Description: 图片裁剪功能测试
* @author XiaoMa
public class PicCutDemoActivity extends Activity implements OnClickListener {
private ImageButton ib =
private ImageView iv =
private Button btn =
private String tp =
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
* 初始化方法实现
private void init() {
ib = (ImageButton) findViewById(R.id.imageButton1);
iv = (ImageView) findViewById(R.id.imageView1);
btn = (Button) findViewById(R.id.button1);
ib.setOnClickListener(this);
iv.setOnClickListener(this);
btn.setOnClickListener(this);
* 控件点击事件实现
* 因为有朋友问不同控件的背景图裁剪怎么实现,
* 我就在这个地方用了三个控件,只为了自己记录学习
* 大家觉得没用的可以跳过啦
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageButton1:
ShowPickDialog();
case R.id.imageView1:
ShowPickDialog();
case R.id.button1:
ShowPickDialog();
* 选择提示对话框
private void ShowPickDialog() {
new AlertDialog.Builder(this)
.setTitle(&设置头像...&)
.setNegativeButton(&相册&, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
* 刚开始,我自己也不知道ACTION_PICK是干嘛的,后来直接看Intent源码,
* 可以发现里面很多东西,Intent是个很强大的东西,大家一定仔细阅读下
Intent intent = new Intent(Intent.ACTION_PICK, null);
* 下面这句话,与其它方式写是一样的效果,如果:
* intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
* intent.setType(&&image/*&);设置数据类型
* 如果朋友们要限制上传到服务器的图片类型时可以直接写如:&image/jpeg 、 image/png等的类型&
* 这个地方小马有个疑问,希望高手解答下:就是这个数据URI与类型为什么要分两种形式来写呀?有什么区别?
intent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
&image/*&);
startActivityForResult(intent, 1);
.setPositiveButton(&拍照&, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.dismiss();
* 下面这句还是老样子,调用快速拍照功能,至于为什么叫快速拍照,大家可以参考如下官方
* 文档,you_sdk_path/docs/guide/topics/media/camera.html
* 我刚看的时候因为太长就认真看,其实是错的,这个里面有用的太多了,所以大家不要认为
* 官方文档太长了就不看了,其实是错的,这个地方小马也错了,必须改正
Intent intent = new Intent(
MediaStore.ACTION_IMAGE_CAPTURE);
//下面这句指定调用相机拍照后的照片存储的路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri
.fromFile(new File(Environment
.getExternalStorageDirectory(),
&xiaoma.jpg&)));
startActivityForResult(intent, 2);
}).show();
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// 如果是直接从相册获取
startPhotoZoom(data.getData());
// 如果是调用相机拍照时
File temp = new File(Environment.getExternalStorageDirectory()
+ &/xiaoma.jpg&);
startPhotoZoom(Uri.fromFile(temp));
// 取得裁剪后的图片
* 非空判断大家一定要验证,如果不验证的话,
* 在剪裁之后如果发现不满意,要重新裁剪,丢弃
* 当前功能时,会报NullException,小马只
* 在这个地方加下,大家可以根据不同情况在合适的
* 地方做判断处理类似情况
if(data != null){
setPicToView(data);
super.onActivityResult(requestCode, resultCode, data);
* 裁剪图片方法实现
* @param uri
public void startPhotoZoom(Uri uri) {
* 至于下面这个Intent的ACTION是怎么知道的,大家可以看下自己路径下的如下网页
* yourself_sdk_path/docs/reference/android/content/Intent.html
* 直接在里面Ctrl+F搜:CROP ,之前小马没仔细看过,其实安卓系统早已经有自带图片裁剪功能,
* 是直接调本地库的,小马不懂C C++
这个不做详细了解去了,有轮子就用轮子,不再研究轮子是怎么
* 制做的了...吼吼
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&, 150);
intent.putExtra(&outputY&, 150);
intent.putExtra(&return-data&, true);
startActivityForResult(intent, 3);
* 保存裁剪之后的图片数据
* @param picdata
private void setPicToView(Intent picdata) {
Bundle extras = picdata.getExtras();
if (extras != null) {
Bitmap photo = extras.getParcelable(&data&);
Drawable drawable = new BitmapDrawable(photo);
* 下面注释的方法是将裁剪之后的图片以Base64Coder的字符方式上
* 传到服务器,QQ头像上传采用的方法跟这个类似
/*ByteArrayOutputStream stream = new ByteArrayOutputStream();
pressFormat.JPEG, 60, stream);
byte[] b = stream.toByteArray();
// 将图片流以字符串形式存储下来
tp = new String(Base64Coder.encodeLines(b));
这个地方大家可以写下给服务器上传图片的实现,直接把tp直接上传就可以了,
服务器处理的方法是服务器那边的事了,吼吼
如果下载到的服务器的数据还是以Base64Coder的形式的话,可以用以下方式转换
为我们可以用的图片类型就OK啦...吼吼
Bitmap dBitmap = BitmapFactory.decodeFile(tp);
Drawable drawable = new BitmapDrawable(dBitmap);
ib.setBackgroundDrawable(drawable);
iv.setBackgroundDrawable(drawable);
下面来看下裁剪中用到的类,大家详细看下头注释:
package com.xiaoma.piccut.
import java.io.F
import android.app.A
import android.app.AlertD
import android.content.DialogI
import android.content.I
import android.graphics.B
import android.graphics.drawable.BitmapD
import android.graphics.drawable.D
import android.net.U
import android.os.B
import android.os.E
import android.provider.MediaS
import android.view.V
import android.view.View.OnClickL
import android.widget.B
import android.widget.ImageB
import android.widget.ImageV
* @Title: PicCutDemoActivity.java
* @Package com.xiaoma.piccut.demo
* @Description: 图片裁剪功能测试
* @author XiaoMa
public class PicCutDemoActivity extends Activity implements OnClickListener {
private ImageButton ib =
private ImageView iv =
private Button btn =
private String tp =
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
* 初始化方法实现
private void init() {
ib = (ImageButton) findViewById(R.id.imageButton1);
iv = (ImageView) findViewById(R.id.imageView1);
btn = (Button) findViewById(R.id.button1);
ib.setOnClickListener(this);
iv.setOnClickListener(this);
btn.setOnClickListener(this);
* 控件点击事件实现
* 因为有朋友问不同控件的背景图裁剪怎么实现,
* 我就在这个地方用了三个控件,只为了自己记录学习
* 大家觉得没用的可以跳过啦
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageButton1:
ShowPickDialog();
case R.id.imageView1:
ShowPickDialog();
case R.id.button1:
ShowPickDialog();
* 选择提示对话框
private void ShowPickDialog() {
new AlertDialog.Builder(this)
.setTitle(&设置头像...&)
.setNegativeButton(&相册&, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
* 刚开始,我自己也不知道ACTION_PICK是干嘛的,后来直接看Intent源码,
* 可以发现里面很多东西,Intent是个很强大的东西,大家一定仔细阅读下
Intent intent = new Intent(Intent.ACTION_PICK, null);
* 下面这句话,与其它方式写是一样的效果,如果:
* intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
* intent.setType(&&image/*&);设置数据类型
* 如果朋友们要限制上传到服务器的图片类型时可以直接写如:&image/jpeg 、 image/png等的类型&
* 这个地方小马有个疑问,希望高手解答下:就是这个数据URI与类型为什么要分两种形式来写呀?有什么区别?
intent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
&image/*&);
startActivityForResult(intent, 1);
.setPositiveButton(&拍照&, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.dismiss();
* 下面这句还是老样子,调用快速拍照功能,至于为什么叫快速拍照,大家可以参考如下官方
* 文档,you_sdk_path/docs/guide/topics/media/camera.html
* 我刚看的时候因为太长就认真看,其实是错的,这个里面有用的太多了,所以大家不要认为
* 官方文档太长了就不看了,其实是错的,这个地方小马也错了,必须改正
Intent intent = new Intent(
MediaStore.ACTION_IMAGE_CAPTURE);
//下面这句指定调用相机拍照后的照片存储的路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri
.fromFile(new File(Environment
.getExternalStorageDirectory(),
&xiaoma.jpg&)));
startActivityForResult(intent, 2);
}).show();
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// 如果是直接从相册获取
startPhotoZoom(data.getData());
// 如果是调用相机拍照时
File temp = new File(Environment.getExternalStorageDirectory()
+ &/xiaoma.jpg&);
startPhotoZoom(Uri.fromFile(temp));
// 取得裁剪后的图片
* 非空判断大家一定要验证,如果不验证的话,
* 在剪裁之后如果发现不满意,要重新裁剪,丢弃
* 当前功能时,会报NullException,小马只
* 在这个地方加下,大家可以根据不同情况在合适的
* 地方做判断处理类似情况
if(data != null){
setPicToView(data);
super.onActivityResult(requestCode, resultCode, data);
* 裁剪图片方法实现
* @param uri
public void startPhotoZoom(Uri uri) {
* 至于下面这个Intent的ACTION是怎么知道的,大家可以看下自己路径下的如下网页
* yourself_sdk_path/docs/reference/android/content/Intent.html
* 直接在里面Ctrl+F搜:CROP ,之前小马没仔细看过,其实安卓系统早已经有自带图片裁剪功能,
* 是直接调本地库的,小马不懂C C++
这个不做详细了解去了,有轮子就用轮子,不再研究轮子是怎么
* 制做的了...吼吼
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&, 150);
intent.putExtra(&outputY&, 150);
intent.putExtra(&return-data&, true);
startActivityForResult(intent, 3);
* 保存裁剪之后的图片数据
* @param picdata
private void setPicToView(Intent picdata) {
Bundle extras = picdata.getExtras();
if (extras != null) {
Bitmap photo = extras.getParcelable(&data&);
Drawable drawable = new BitmapDrawable(photo);
* 下面注释的方法是将裁剪之后的图片以Base64Coder的字符方式上
* 传到服务器,QQ头像上传采用的方法跟这个类似
/*ByteArrayOutputStream stream = new ByteArrayOutputStream();
pressFormat.JPEG, 60, stream);
byte[] b = stream.toByteArray();
// 将图片流以字符串形式存储下来
tp = new String(Base64Coder.encodeLines(b));
这个地方大家可以写下给服务器上传图片的实现,直接把tp直接上传就可以了,
服务器处理的方法是服务器那边的事了,吼吼
如果下载到的服务器的数据还是以Base64Coder的形式的话,可以用以下方式转换
为我们可以用的图片类型就OK啦...吼吼
Bitmap dBitmap = BitmapFactory.decodeFile(tp);
Drawable drawable = new BitmapDrawable(dBitmap);
ib.setBackgroundDrawable(drawable);
iv.setBackgroundDrawable(drawable);
& & & & & 最后,小马还把小DEMO源码放在附件里面,有需要的朋友可以下载下来,共同交流学习,也恳请高人回答下小马在文章注释中提出的问题,谢谢,文章是小马急急忙忙在家写的,在网吧发的,晕...不是我有多用功,这边下雨,讨厌下雨,下雨我就郁闷,来网吧玩的,顺带发下文章,吼吼,该玩的时候死命的玩,该工作的时候死命的工作,年轻时疯狂,老了不后悔,吼吼,加油加油!大家工作,也注意身体健康,嘿嘿,你懂的,不解释...哈哈
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:4989次
排名:千里之外
http://mzh3344258./Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪)
最近有看到有朋友在讨论的裁剪上传是怎么实现的,吼吼,也没做过,好奇之下学习下,发现以前项目中有类型的功能,结合官方文档里面的解释,就更好玩了,周末,急急忙忙写的,记录在博客里,希望能与大家交流学习,也恳请高手能解答小马在代码注释中提出的疑问,不管有没有人回答,小马先谢谢了,一样的,先看下效果图(效果图小马不解释了,直接流水写下去,小马是直接在模拟器里写的,能在真机上使用,因为很简单),再看代码是怎么实现的:
一:主布局界面
二:点击控件触发事件后效果图
三:拍照完之后效果图
四:裁剪界面效果图
五:点击相册后返回的图片效果图
六:裁剪完从相册PICK的保存后的效果图&
下面直接来看下主控制类代码,如下:
1.&package com.xiaoma.piccut.&
3.&import java.io.F&
4.&import android.app.A&
5.&import android.app.AlertD&
6.&import android.content.DialogI&
7.&import android.content.I&
8.&import android.graphics.B&
9.&import android.graphics.drawable.BitmapD&
10.&import android.graphics.drawable.D&
11.&import android.net.U&
12.&import android.os.B&
13.&import android.os.E&
14.&import android.provider.MediaS&
15.&import android.view.V&
16.&import android.view.View.OnClickL&
17.&import android.widget.B&
18.&import android.widget.ImageB&
19.&import android.widget.ImageV&
21.& * @Title: PicCutDemoActivity.java&
22.& * @Package com.xiaoma.piccut.demo&
23.& * @Description: 图片裁剪功能测试&
24.& * @author XiaoMa&
26.&public class PicCutDemoActivity extends Activity implements OnClickListener {&
28.&&&& private ImageButton ib =&
29.&&&& private ImageView iv =&
30.&&&& private Button btn =&
31.&&&& private String tp =&
34.&&&& /** Called when the activity is first created. */
35.&&&& @Override
36.&&&& public void onCreate(Bundle savedInstanceState) {&
37.&&&&&&&& super.onCreate(savedInstanceState);&
38.&&&&&&&& setContentView(R.layout.main);&
39.&&&&&&&& //初始化&
40.&&&&&&&& init();&
41.&&&& }&
43.&&&& /**&
44.&&&&& * 初始化方法实现&
45.&&&&& */
46.&&&& private void init() {&
47.&&&&&&&& ib = (ImageButton) findViewById(R.id.imageButton1);&
48.&&&&&&&& iv = (ImageView) findViewById(R.id.imageView1);&
49.&&&&&&&& btn = (Button) findViewById(R.id.button1);&
50.&&&&&&&& ib.setOnClickListener(this);&
51.&&&&&&&& iv.setOnClickListener(this);&
52.&&&&&&&& btn.setOnClickListener(this);&
53.&&&& }&
56.&&&& /**&
57.&&&&& * 控件点击事件实现&
58.&&&&& *&&
59.&&&&& * 因为有朋友问不同控件的背景图裁剪怎么实现,&
60.&&&&& * 我就在这个地方用了三个控件,只为了自己记录学习&
61.&&&&& * 大家觉得没用的可以跳过啦&
62.&&&&& */
63.&&&& @Override
64.&&&& public void onClick(View v) {&
65.&&&&&&&& switch (v.getId()) {&
66.&&&&&&&& case R.id.imageButton1:&
67.&&&&&&&&&&&& ShowPickDialog();&
68.&&&&&&&&&&&&&
69.&&&&&&&& case R.id.imageView1:&
70.&&&&&&&&&&&& ShowPickDialog();&
71.&&&&&&&&&&&&&
72.&&&&&&&& case R.id.button1:&
73.&&&&&&&&&&&& ShowPickDialog();&
74.&&&&&&&&&&&&&
76.&&&&&&&& default:&
77.&&&&&&&&&&&&&
78.&&&&&&&& }&
79.&&&& }&
81.&&&& /**&
82.&&&&& * 选择提示对话框&
83.&&&&& */
84.&&&& private void ShowPickDialog() {&
85.&&&&&&&& new AlertDialog.Builder(this)&
86.&&&&&&&&&&&&&&&& .setTitle(&设置头像...&)&
87.&&&&&&&&&&&&&&&& .setNegativeButton(&相册&, new DialogInterface.OnClickListener() {&
88.&&&&&&&&&&&&&&&&&&&& public void onClick(DialogInterface dialog, int which) {&
89.&&&&&&&&&&&&&&&&&&&&&&&& dialog.dismiss();&
90.&&&&&&&&&&&&&&&&&&&&&&&& /**&
91.&&&&&&&&&&&&&&&&&&&&&&&&& * 刚开始,我自己也不知道ACTION_PICK是干嘛的,后来直接看Intent,&
92.&&&&&&&&&&&&&&&&&&&&&&&&& * 可以发现里面很多东西,Intent是个很强大的东西,大家一定仔细下&
93.&&&&&&&&&&&&&&&&&&&&&&&&& */
94.&&&&&&&&&&&&&&&&&&&&&&&& Intent intent = new Intent(Intent.ACTION_PICK, null);&
95.&&&&&&&&&&&&&&&&&&&&&&&&&&
96.&&&&&&&&&&&&&&&&&&&&&&&& /**&
97.&&&&&&&&&&&&&&&&&&&&&&&&& * 下面这句话,与其它方式写是一样的效果,如果:&
98.&&&&&&&&&&&&&&&&&&&&&&&&& * intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);&
99.&&&&&&&&&&&&&&&&&&&&&&&&& * intent.setType(&&image/*&);设置数据类型&
100.&&&&&&&&&&&&&&&&&&&&&&&&& * 如果朋友们要限制上传到服务器的图片类型时可以直接写如:&image/jpeg 、 image/png等的类型&&
101.&&&&&&&&&&&&&&&&&&&&&&&&& * 这个地方小马有个疑问,希望高手解答下:就是这个数据URI与类型为什么要分两种形式来写呀?有什么区别?&
102.&&&&&&&&&&&&&&&&&&&&&&&&& */
103.&&&&&&&&&&&&&&&&&&&&&&&& intent.setDataAndType(&
104.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& MediaStore.Images.Media.EXTERNAL_CONTENT_URI,&
105.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &image/*&);&
106.&&&&&&&&&&&&&&&&&&&&&&&& startActivityForResult(intent, 1);&
108.&&&&&&&&&&&&&&&&&&&& }&
109.&&&&&&&&&&&&&&&& })&
110.&&&&&&&&&&&&&&&& .setPositiveButton(&拍照&, new DialogInterface.OnClickListener() {&
111.&&&&&&&&&&&&&&&&&&&& public void onClick(DialogInterface dialog, int whichButton) {&
112.&&&&&&&&&&&&&&&&&&&&&&&& dialog.dismiss();&
113.&&&&&&&&&&&&&&&&&&&&&&&& /**&
114.&&&&&&&&&&&&&&&&&&&&&&&&& * 下面这句还是老样子,调用快速拍照功能,至于为什么叫快速拍照,大家可以参考如下官方&
115.&&&&&&&&&&&&&&&&&&&&&&&&& * 文档,you_sdk_path/docs/guide/topics/media/camera.html&
116.&&&&&&&&&&&&&&&&&&&&&&&&& * 我刚看的时候因为太长就认真看,其实是错的,这个里面有用的太多了,所以大家不要认为&
117.&&&&&&&&&&&&&&&&&&&&&&&&& * 官方文档太长了就不看了,其实是错的,这个地方小马也错了,必须改正&
118.&&&&&&&&&&&&&&&&&&&&&&&&& */&
119.&&&&&&&&&&&&&&&&&&&&&&&& Intent intent = new Intent(&
120.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& MediaStore.ACTION_IMAGE_CAPTURE);&
121.&&&&&&&&&&&&&&&&&&&&&&&& //下面这句指定调用相机拍照后的照片存储的路径&
122.&&&&&&&&&&&&&&&&&&&&&&&& intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri&
123.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& .fromFile(new File(Environment&
124.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& .getExternalStorageDirectory(),&
125.&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &xiaoma.jpg&)));&
126.&&&&&&&&&&&&&&&&&&&&&&&& startActivityForResult(intent, 2);&
127.&&&&&&&&&&&&&&&&&&&& }&
128.&&&&&&&&&&&&&&&& }).show();&
129.&&&& }&
131.&&&& @Override
132.&&&& protected void onActivityResult(int requestCode, int resultCode, Intent data) {&
133.&&&&&&&& switch (requestCode) {&
134.&&&&&&&& // 如果是直接从相册获取&
135.&&&&&&&& case 1:&
136.&&&&&&&&&&&& startPhotoZoom(data.getData());&
137.&&&&&&&&&&&&&
138.&&&&&&&& // 如果是调用相机拍照时&
139.&&&&&&&& case 2:&
140.&&&&&&&&&&&& File temp = new File(Environment.getExternalStorageDirectory()&
141.&&&&&&&&&&&&&&&&&&&& + &/xiaoma.jpg&);&
142.&&&&&&&&&&&& startPhotoZoom(Uri.fromFile(temp));&
143.&&&&&&&&&&&&&
144.&&&&&&&& // 取得裁剪后的图片&
145.&&&&&&&& case 3:&
146.&&&&&&&&&&&& /**&
147.&&&&&&&&&&&&& * 非空判断大家一定要验证,如果不验证的话,&
148.&&&&&&&&&&&&& * 在剪裁之后如果发现不满意,要重新裁剪,丢弃&
149.&&&&&&&&&&&&& * 当前功能时,会报NullException,小马只&
150.&&&&&&&&&&&&& * 在这个地方加下,大家可以根据不同情况在合适的&
151.&&&&&&&&&&&&& * 地方做判断处理类似情况&
152.&&&&&&&&&&&&& *&&
153.&&&&&&&&&&&&& */
154.&&&&&&&&&&&& if(data != null){&
155.&&&&&&&&&&&&&&&& setPicToView(data);&
156.&&&&&&&&&&&& }&
157.&&&&&&&&&&&&&
158.&&&&&&&& default:&
159.&&&&&&&&&&&&&
161.&&&&&&&& }&
162.&&&&&&&& super.onActivityResult(requestCode, resultCode, data);&
163.&&&& }&
164.&&&&&&
165.&&&& /**&
166.&&&&& * 裁剪图片方法实现&
167.&&&&& * @param uri&
168.&&&&& */
169.&&&& public void startPhotoZoom(Uri uri) {&
170.&&&&&&&& /*&
171.&&&&&&&&& * 至于下面这个Intent的ACTION是怎么知道的,大家可以看下自己路径下的如下网页&
172.&&&&&&&&& * yourself_sdk_path/docs/reference/android/content/Intent.html&
173.&&&&&&&&& * 直接在里面Ctrl+F搜:CROP ,之前小马没仔细看过,其实安卓早已经有自带图片裁剪功能,&
174.&&&&&&&&& * 是直接调本地库的,小马不懂C C++& 这个不做详细了解去了,有轮子就用轮子,不再研究轮子是怎么&
175.&&&&&&&&& * 制做的了...吼吼&
176.&&&&&&&&& */
177.&&&&&&&& Intent intent = new Intent(&com.android.camera.action.CROP&);&
178.&&&&&&&& intent.setDataAndType(uri, &image/*&);&
179.&&&&&&&& //下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪&
180.&&&&&&&& intent.putExtra(&crop&, &true&);&
181.&&&&&&&& // ectX aspectY 是宽高的比例&
182.&&&&&&&& intent.putExtra(&aspectX&, 1);&
183.&&&&&&&& intent.putExtra(&aspectY&, 1);&
184.&&&&&&&& // outputX outputY 是裁剪图片宽高&
185.&&&&&&&& intent.putExtra(&outputX&, 150);&
186.&&&&&&&& intent.putExtra(&outputY&, 150);&
187.&&&&&&&& intent.putExtra(&return-data&, true);&
188.&&&&&&&& startActivityForResult(intent, 3);&
189.&&&& }&
190.&&&&&&
191.&&&& /**&
192.&&&&& * 保存裁剪之后的图片数据&
193.&&&&& * @param picdata&
194.&&&&& */&
195.&&&& private void setPicToView(Intent picdata) {&
196.&&&&&&&& Bundle extras = picdata.getExtras();&
197.&&&&&&&& if (extras != null) {&
198.&&&&&&&&&&&& Bitmap photo = extras.getParcelable(&data&);&
199.&&&&&&&&&&&& Drawable drawable = new BitmapDrawable(photo);&
200.&&&&&&&&&&&&&&
201.&&&&&&&&&&&& /**&
202.&&&&&&&&&&&&& * 下面注释的方法是将裁剪之后的图片以Base64Coder的字符方式上&
203.&&&&&&&&&&&&& * 传到服务器,QQ头像上传采用的方法跟这个类似&
204.&&&&&&&&&&&&& */
205.&&&&&&&&&&&&&&
206.&&&&&&&&&&&& /*ByteArrayOutputStream stream = new ByteArrayOutputStream();&
207.&&&&&&&&&&&& pressFormat.JPEG, 60, stream);&
208.&&&&&&&&&&&& byte[] b = stream.toByteArray();&
209.&&&&&&&&&&&& // 将图片流以字符串形式存储下来&
210.&&&&&&&&&&&&&&
211.&&&&&&&&&&&& tp = new String(Base64Coder.encodeLines(b));&
212.&&&&&&&&&&&& 这个地方大家可以写下给服务器上传图片的实现,直接把tp直接上传就可以了,&
213.&&&&&&&&&&&& 服务器处理的方法是服务器那边的事了,吼吼&
214.&&&&&&&&&&&&&&
215.&&&&&&&&&&&& 如果下载到的服务器的数据还是以Base64Coder的形式的话,可以用以下方式转换&
216.&&&&&&&&&&&& 为我们可以用的图片类型就OK啦...吼吼&
217.&&&&&&&&&&&& Bitmap dBitmap = BitmapFactory.decodeFile(tp);&
218.&&&&&&&&&&&& Drawable drawable = new BitmapDrawable(dBitmap);&
219.&&&&&&&&&&&& */
220.&&&&&&&&&&&& ib.setBackgroundDrawable(drawable);&
221.&&&&&&&&&&&& iv.setBackgroundDrawable(drawable);&
222.&&&&&&&& }&
223.&&&& }&
下面来看下裁剪中用到的类,大家详细看下头注释:
1.&package com.xiaoma.piccut.&
7.& * 下面这些注释是下载这个类的时候本来就有的,本来要删除的,但看了下竟然是license,吼吼,&
8.& * 好东西,留在注释里,以备不时之用,大家有需要加license的可以到下面的网址找哦&
11.&//EPL, Eclipse Public License, V1.0 or later, &
12.&//LGPL, GNU Lesser General Public License, V2.1 or later, &
13.&//GPL, GNU General Public License, V2 or later, &
14.&//AL, Apache License, V2.0 or later, &
15.&//BSD, BSD License, &
17.&* A Base64 encoder/decoder.&
19.&* &p&&
20.&* This class is used to encode and decode data in Base64 format as described in RFC 1521.&
22.&* &p&&
23.&* Project home page: &a href=&&&
24.&* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland&br&&
25.&* Multi-licensed: EPL / LGPL / GPL / AL / BSD.&
29.& * 这个类在上面注释的网址中有,大家可以自行下载下,也可以直接用这个,&
30.& * 公开的Base64Coder类(不用深究它是怎么实现的,&
31.& * 还是那句话,有轮子直接用轮子),好用的要死人了...&
32.& * 小马也很无耻的引用了这个网址下的东东,吼吼...&
33.&* @Title: Base64Coder.java&
34.&* @Package com.xiaoma.piccut.demo&
35.&* @Description: TODO&
36.&* @author XiaoMa&
39.&public class Base64Coder {&
41.&//The line separator string of the operating system.&
42.&private static final String systemLineSeparator = System.getProperty(&line.separator&);&
44.&//Mapping table from 6-bit nibbles to Base64 characters.&
45.&private static char[]&&& map1 = new char[64];&
46.&static {&
47.&&& int i=0;&
48.&&& for (char c='A'; c&='Z'; c++) map1[i++] =&
49.&&& for (char c='a'; c&='z'; c++) map1[i++] =&
50.&&& for (char c='0'; c&='9'; c++) map1[i++] =&
51.&&& map1[i++] = '+'; map1[i++] = '/'; }&
53.&//Mapping table from Base64 characters to 6-bit nibbles.&
54.&private static byte[]&&& map2 = new byte[128];&
55.&static {&
56.&&& for (int i=0; i&map2. i++) map2[i] = -1;&
57.&&& for (int i=0; i&64; i++) map2[map1[i]] = (byte)i; }&
60.&* Encodes a string into Base64 format.&
61.&* No blanks or line breaks are inserted.&
62.&* @param s& A String to be encoded.&
63.&* @return&& A String containing the Base64 encoded data.&
65.&public static String encodeString (String s) {&
66.&return new String(encode(s.getBytes())); }&
69.&* Encodes a byte array into Base 64 format and breaks the output into lines of 76 characters.&
70.&* This method is compatible with &code&sun.misc.BASE64Encoder.encodeBuffer(byte[])&/code&.&
71.&* @param in& An array containing the data bytes to be encoded.&
72.&* @return&&& A String containing the Base64 encoded data, broken into lines.&
74.&public static String encodeLines (byte[] in) {&
75.&return encodeLines(in, 0, in.length, 76, systemLineSeparator); }&
78.&* Encodes a byte array into Base 64 format and breaks the output into lines.&
79.&* @param in&&&&&&&&&&& An array containing the data bytes to be encoded.&
80.&* @param iOff&&&&&&&&& Offset of the first byte in &code&in&/code& to be processed.&
81.&* @param iLen&&&&&&&&& Number of bytes to be processed in &code&in&/code&, starting at &code&iOff&/code&.&
82.&* @param lineLen&&&&&& Line length for the output data. Should be a multiple of 4.&
83.&* @param lineSeparator The line separator to be used to separate the output lines.&
84.&* @return&&&&&&&&&&&&& A String containing the Base64 encoded data, broken into lines.&
86.&public static String encodeLines (byte[] in, int iOff, int iLen, int lineLen, String lineSeparator) {&
87.&int blockLen = (lineLen*3) / 4;&
88.&if (blockLen &= 0) throw new IllegalArgumentException();&
89.&int lines = (iLen+blockLen-1) / blockL&
90.&int bufLen = ((iLen+2)/3)*4 + lines*lineSeparator.length();&
91.&StringBuilder buf = new StringBuilder(bufLen);&
92.&int ip = 0;&
93.&while (ip & iLen) {&
94.&&& int l = Math.min(iLen-ip, blockLen);&
95.&&& buf.append (encode(in, iOff+ip, l));&
96.&&& buf.append (lineSeparator);&
97.&&& ip += }&
98.&return buf.toString(); }&
101.&* Encodes a byte array into Base64 format.&
102.&* No blanks or line breaks are inserted in the output.&
103.&* @param in& An array containing the data bytes to be encoded.&
104.&* @return&&& A character array containing the Base64 encoded data.&
106.&public static char[] encode (byte[] in) {&
107.&return encode(in, 0, in.length); }&
110.&* Encodes a byte array into Base64 format.&
111.&* No blanks or line breaks are inserted in the output.&
112.&* @param in&&& An array containing the data bytes to be encoded.&
113.&* @param iLen& Number of bytes to process in &code&in&/code&.&
114.&* @return&&&&& A character array containing the Base64 encoded data.&
116.&public static char[] encode (byte[] in, int iLen) {&
117.&return encode(in, 0, iLen); }&
120.&* Encodes a byte array into Base64 format.&
121.&* No blanks or line breaks are inserted in the output.&
122.&* @param in&&& An array containing the data bytes to be encoded.&
123.&* @param iOff& Offset of the first byte in &code&in&/code& to be processed.&
124.&* @param iLen& Number of bytes to process in &code&in&/code&, starting at &code&iOff&/code&.&
125.&* @return&&&&& A character array containing the Base64 encoded data.&
127.&public static char[] encode (byte[] in, int iOff, int iLen) {&
128.&int oDataLen = (iLen*4+2)/3;&&&&&& // output length without padding&
129.&int oLen = ((iLen+2)/3)*4;&&&&&&&& // output length including padding&
130.&char[] out = new char[oLen];&
131.&int ip = iO&
132.&int iEnd = iOff + iL&
133.&int op = 0;&
134.&while (ip & iEnd) {&
135.&&& int i0 = in[ip++] & 0&
136.&&& int i1 = ip & iEnd ? in[ip++] & 0xff : 0;&
137.&&& int i2 = ip & iEnd ? in[ip++] & 0xff : 0;&
138.&&& int o0 = i0 &&& 2;&
139.&&& int o1 = ((i0 &&& 3) && 4) | (i1 &&& 4);&
140.&&& int o2 = ((i1 & 0xf) && 2) | (i2 &&& 6);&
141.&&& int o3 = i2 & 0x3F;&
142.&&& out[op++] = map1[o0];&
143.&&& out[op++] = map1[o1];&
144.&&& out[op] = op & oDataLen ? map1[o2] : '='; op++;&
145.&&& out[op] = op & oDataLen ? map1[o3] : '='; op++; }&
149.&* Decodes a string from Base64 format.&
150.&* No blanks or line breaks are allowed within the Base64 encoded input data.&
151.&* @param s& A Base64 String to be decoded.&
152.&* @return&& A String containing the decoded data.&
153.&* @throws&& IllegalArgumentException If the input is not valid Base64 encoded data.&
155.&public static String decodeString (String s) {&
156.&return new String(decode(s)); }&
159.&* Decodes a byte array from Base64 format and ignores line separators, tabs and blanks.&
160.&* CR, LF, Tab and Space characters are ignored in the input data.&
161.&* This method is compatible with &code&sun.misc.BASE64Decoder.decodeBuffer(String)&/code&.&
162.&* @param s& A Base64 String to be decoded.&
163.&* @return&& An array containing the decoded data bytes.&
164.&* @throws&& IllegalArgumentException If the input is not valid Base64 encoded data.&
166.&public static byte[] decodeLines (String s) {&
167.&char[] buf = new char[s.length()+3];&
168.&int p = 0;&
169.&for (int ip = 0; ip & s.length(); ip++) {&
170.&&& char c = s.charAt(ip);&
171.&&& if (c != ' ' && c != '\r' && c != '\n' && c != '\t')&
172.&&&&&& buf[p++] = }&
173.&&& while ((p % 4) != 0)&
174.&&&&&&& buf[p++] = '0';&
175.&&&&&&
176.&return decode(buf, 0, p); }&
179.&* Decodes a byte array from Base64 format.&
180.&* No blanks or line breaks are allowed within the Base64 encoded input data.&
181.&* @param s& A Base64 String to be decoded.&
182.&* @return&& An array containing the decoded data bytes.&
183.&* @throws&& IllegalArgumentException If the input is not valid Base64 encoded data.&
185.&public static byte[] decode (String s) {&
186.&return decode(s.toCharArray()); }&
189.&* Decodes a byte array from Base64 format.&
190.&* No blanks or line breaks are allowed within the Base64 encoded input data.&
191.&* @param in& A character array containing the Base64 encoded data.&
192.&* @return&&& An array containing the decoded data bytes.&
193.&* @throws&&& IllegalArgumentException If the input is not valid Base64 encoded data.&
195.&public static byte[] decode (char[] in) {&
196.&return decode(in, 0, in.length); }&
199.&* Decodes a byte array from Base64 format.&
200.&* No blanks or line breaks are allowed within the Base64 encoded input data.&
201.&* @param in&&& A character array containing the Base64 encoded data.&
202.&* @param iOff& Offset of the first character in &code&in&/code& to be processed.&
203.&* @param iLen& Number of characters to process in &code&in&/code&, starting at &code&iOff&/code&.&
204.&* @return&&&&& An array containing the decoded data bytes.&
205.&* @throws&&&&& IllegalArgumentException If the input is not valid Base64 encoded data.&
207.&public static byte[] decode (char[] in, int iOff, int iLen) {&
208.&if (iLen%4 != 0) throw new IllegalArgumentException (&Length of Base64 encoded input string is not a multiple of 4.&);&
209.&while (iLen & 0 && in[iOff+iLen-1] == '=') iLen--;&
210.&int oLen = (iLen*3) / 4;&
211.&byte[] out = new byte[oLen];&
212.&int ip = iO&
213.&int iEnd = iOff + iL&
214.&int op = 0;&
215.&while (ip & iEnd) {&
216.&&& int i0 = in[ip++];&
217.&&& int i1 = in[ip++];&
218.&&& int i2 = ip & iEnd ? in[ip++] : 'A';&
219.&&& int i3 = ip & iEnd ? in[ip++] : 'A';&
220.&&& if (i0 & 127 || i1 & 127 || i2 & 127 || i3 & 127)&
221.&&&&&& throw new IllegalArgumentException (&Illegal character in Base64 encoded data.&);&
222.&&& int b0 = map2[i0];&
223.&&& int b1 = map2[i1];&
224.&&& int b2 = map2[i2];&
225.&&& int b3 = map2[i3];&
226.&&& if (b0 & 0 || b1 & 0 || b2 & 0 || b3 & 0)&
227.&&&&&& throw new IllegalArgumentException (&Illegal character in Base64 encoded data.&);&
228.&&& int o0 = ( b0&&&&&& &&2) | (b1&&&4);&
229.&&& int o1 = ((b1 & 0xf)&&4) | (b2&&&2);&
230.&&& int o2 = ((b2 &&& 3)&&6) |& b3;&
231.&&& out[op++] = (byte)o0;&
232.&&& if (op&oLen) out[op++] = (byte)o1;&
233.&&& if (op&oLen) out[op++] = (byte)o2; }&
236.&//Dummy constructor.&
237.&private Base64Coder() {}&
239.&} // end class Base64Coder
&&&&&&&&&& 最后,小马还把小DEMO源码放在附件里面,有需要的朋友可以下载下来,共同交流学习,也恳请高人回答下小马在文章注释中提出的问题,谢谢,文章是小马急急忙忙在家写的,在网吧发的,晕...不是我有多用功,这边下雨,讨厌下雨,下雨我就郁闷,来网吧玩的,顺带发下文章,吼吼,该玩的时候死命的玩,该工作的时候死命的工作,年轻时疯狂,老了不后悔,吼吼,加油加油!大家工作,也注意身体健康,嘿嘿,你懂的,不解释...哈哈
&摘自& 酷_莫名简单&
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

我要回帖

更多关于 android 实现上传头像 的文章

 

随机推荐