├── .gitignore ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── chaychan │ │ └── androidnadaption │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── chaychan │ │ │ └── androidnadaption │ │ │ ├── MainActivity.java │ │ │ ├── MyApplication.java │ │ │ ├── listener │ │ │ └── PermissionListener.java │ │ │ └── utils │ │ │ ├── FileUtils.java │ │ │ ├── ImageTools.java │ │ │ └── UIUtils.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── file_provider_paths.xml │ └── test │ └── java │ └── com │ └── chaychan │ └── androidnadaption │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | /.idea 10 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.chaychan.androidnadaption" 9 | minSdkVersion 16 10 | targetSdkVersion 24 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:24.2.1' 26 | } 27 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in G:\SDK\AndroidStudioSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/chaychan/androidnadaption/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.chaychan.androidnadaption; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/chaychan/androidnadaption/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.chaychan.androidnadaption; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.database.Cursor; 7 | import android.graphics.Bitmap; 8 | import android.net.Uri; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.provider.MediaStore; 12 | import android.support.annotation.NonNull; 13 | import android.support.v4.app.ActivityCompat; 14 | import android.support.v4.content.ContextCompat; 15 | import android.support.v4.content.FileProvider; 16 | import android.support.v7.app.AppCompatActivity; 17 | import android.view.View; 18 | import android.widget.ImageView; 19 | 20 | import com.chaychan.androidnadaption.listener.PermissionListener; 21 | import com.chaychan.androidnadaption.utils.FileUtils; 22 | import com.chaychan.androidnadaption.utils.ImageTools; 23 | import com.chaychan.androidnadaption.utils.UIUtils; 24 | 25 | import java.io.File; 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | 29 | public class MainActivity extends AppCompatActivity { 30 | 31 | private PermissionListener permissionListener; 32 | 33 | public static final int REQ_TAKE_PHOTO = 100; 34 | public static final int REQ_ALBUM = 101; 35 | public static final int REQ_ZOOM = 102; 36 | 37 | private Uri outputUri; 38 | private String imgPath; 39 | private ImageView ivPhoto; 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_main); 45 | 46 | ivPhoto = (ImageView) findViewById(R.id.iv_photo); 47 | } 48 | 49 | 50 | /** 51 | * 拍照,使用存储卡路径(需要申请存储权限),即图片的路径在 存储卡目录下 -> 包名 -> icon文件夹下 52 | */ 53 | public void takePhoto(View view){ 54 | imgPath = FileUtils.generateImgePathInStoragePath(); 55 | 56 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 57 | //如果是6.0或6.0以上,则要申请运行时权限,这里需要申请拍照的权限 58 | requestRuntimePermission(new String[]{Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, new PermissionListener() { 59 | @Override 60 | public void onGranted() { 61 | //开启摄像头,拍照完的图片保存在对应路径下 62 | openCamera(imgPath); 63 | } 64 | 65 | @Override 66 | public void onDenied(List deniedPermissions) { 67 | UIUtils.showToast("所需权限被拒绝"); 68 | } 69 | }); 70 | return; 71 | } 72 | 73 | openCamera(imgPath); 74 | } 75 | 76 | /**打开相册*/ 77 | public void openAlbum(View view){ 78 | Intent intent = new Intent(Intent.ACTION_PICK, null); 79 | intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 80 | "image/*"); 81 | startActivityForResult(intent, REQ_ALBUM); 82 | } 83 | 84 | /**开启摄像机*/ 85 | private void openCamera(String imgPath) { 86 | // 指定调用相机拍照后照片的储存路径 87 | File imgFile = new File(imgPath); 88 | Uri imgUri = null; 89 | if (Build.VERSION.SDK_INT >= 24) { 90 | //如果是7.0或以上 91 | imgUri = FileProvider.getUriForFile(this, UIUtils.getPackageName() + ".fileprovider", imgFile); 92 | } else { 93 | imgUri = Uri.fromFile(imgFile); 94 | } 95 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 96 | intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri); 97 | startActivityForResult(intent, REQ_TAKE_PHOTO); 98 | } 99 | 100 | /** 101 | * 申请运行时权限 102 | */ 103 | public void requestRuntimePermission(String[] permissions, PermissionListener permissionListener) { 104 | this.permissionListener = permissionListener; 105 | List permissionList = new ArrayList<>(); 106 | for (String permission : permissions) { 107 | if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { 108 | permissionList.add(permission); 109 | } 110 | } 111 | 112 | if (!permissionList.isEmpty()) { 113 | ActivityCompat.requestPermissions(this, permissionList.toArray(new String[permissionList.size()]), 1); 114 | } else { 115 | permissionListener.onGranted(); 116 | } 117 | } 118 | 119 | 120 | @Override 121 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 122 | switch (resultCode) { 123 | case RESULT_OK://调用图片选择处理成功 124 | String zoomImgPath = ""; 125 | Bitmap bm = null; 126 | File temFile = null; 127 | File srcFile = null; 128 | File outPutFile = null; 129 | switch (requestCode) { 130 | case REQ_TAKE_PHOTO:// 拍照后在这里回调 131 | srcFile = new File(imgPath); 132 | outPutFile = new File(FileUtils.generateImgePathInStoragePath()); 133 | outputUri = Uri.fromFile(outPutFile); 134 | FileUtils.startPhotoZoom(this, srcFile, outPutFile, REQ_ZOOM);// 发起裁剪请求 135 | break; 136 | 137 | case REQ_ALBUM:// 选择相册中的图片 138 | if (data != null) { 139 | Uri sourceUri = data.getData(); 140 | String[] proj = {MediaStore.Images.Media.DATA}; 141 | 142 | // 好像是android多媒体数据库的封装接口,具体的看Android文档 143 | Cursor cursor = managedQuery(sourceUri, proj, null, null, null); 144 | 145 | // 按我个人理解 这个是获得用户选择的图片的索引值 146 | int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 147 | // 将光标移至开头 ,这个很重要,不小心很容易引起越界 148 | cursor.moveToFirst(); 149 | // 最后根据索引值获取图片路径 150 | imgPath = cursor.getString(column_index); 151 | 152 | srcFile = new File(imgPath); 153 | outPutFile = new File(FileUtils.generateImgePathInStoragePath()); 154 | outputUri = Uri.fromFile(outPutFile); 155 | FileUtils.startPhotoZoom(this, srcFile, outPutFile, REQ_ZOOM);// 发起裁剪请求 156 | } 157 | break; 158 | 159 | case REQ_ZOOM://裁剪后回调 160 | // Bundle extras = data.getExtras(); 161 | if (data != null) { 162 | // bm = extras.getParcelable("data"); 163 | if (outputUri != null) { 164 | bm = ImageTools.decodeUriAsBitmap(outputUri); 165 | //如果是拍照的,删除临时文件 166 | temFile = new File(imgPath); 167 | if (temFile.exists()) { 168 | temFile.delete(); 169 | } 170 | 171 | String scaleImgPath = FileUtils.saveBitmapByQuality(bm, 80);//复制并压缩到自己的目录并压缩 172 | //进行上传,上传成功后显示新图片,这里不演示上传的逻辑,上传只需将scaleImgPath路径下的文件上传即可。 173 | ivPhoto.setImageBitmap(bm);//显示在iv上 174 | } 175 | } else { 176 | UIUtils.showToast("选择图片发生错误,图片可能已经移位或删除"); 177 | } 178 | break; 179 | } 180 | break; 181 | } 182 | } 183 | 184 | @Override 185 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 186 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 187 | switch (requestCode) { 188 | case 1: 189 | if (grantResults.length > 0) { 190 | List deniedPermissions = new ArrayList<>(); 191 | for (int i = 0; i < grantResults.length; i++) { 192 | int grantResult = grantResults[i]; 193 | String permission = permissions[i]; 194 | if (grantResult != PackageManager.PERMISSION_GRANTED) { 195 | deniedPermissions.add(permission); 196 | } 197 | } 198 | if (deniedPermissions.isEmpty()) { 199 | permissionListener.onGranted(); 200 | } else { 201 | permissionListener.onDenied(deniedPermissions); 202 | } 203 | } 204 | break; 205 | } 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /app/src/main/java/com/chaychan/androidnadaption/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.chaychan.androidnadaption; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.os.Process; 8 | 9 | 10 | 11 | public class MyApplication extends Application { 12 | 13 | private static final String TAG = MyApplication.class.getSimpleName() ; 14 | private static Context mContext; 15 | private static Thread mMainThread; 16 | private static long mMainThreadId; 17 | private static Looper mMainLooper; 18 | private static Handler mHandler; 19 | 20 | public static Context getContext() { 21 | return mContext; 22 | } 23 | 24 | public static Thread getMainThread() { 25 | return mMainThread; 26 | } 27 | 28 | public static long getMainThreadId() { 29 | return mMainThreadId; 30 | } 31 | 32 | public static Looper getMainThreadLooper() { 33 | return mMainLooper; 34 | } 35 | 36 | public static Handler getHandler() { 37 | return mHandler; 38 | } 39 | 40 | 41 | @Override 42 | public void onCreate() {// 程序的入口 43 | // Thread.setDefaultUncaughtExceptionHandler(new MyHandler());//设置全局异常捕获器 44 | 45 | // 初始化一些,常用的属性,然后放到盒子里面来 46 | // 上下文 47 | mContext = getApplicationContext(); 48 | 49 | // 主线程 50 | mMainThread = Thread.currentThread(); 51 | 52 | // 主线程id 53 | mMainThreadId = Process.myTid(); 54 | 55 | // tid thread 56 | // uid user 57 | // pid process 58 | 59 | mMainLooper = getMainLooper(); 60 | 61 | mHandler = new Handler(); 62 | 63 | super.onCreate(); 64 | } 65 | 66 | 67 | class MyHandler implements Thread.UncaughtExceptionHandler { 68 | 69 | @Override 70 | public void uncaughtException(Thread thread, Throwable ex) { 71 | ex.printStackTrace(); 72 | Process.killProcess(Process.myPid());//关闭当前进程 73 | } 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/chaychan/androidnadaption/listener/PermissionListener.java: -------------------------------------------------------------------------------- 1 | package com.chaychan.androidnadaption.listener; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author JayChan 7 | * @description: 权限申请回调的接口 8 | * @date 2017/3/25 10:41 9 | * Copyright 2017 Youjiang 10 | * Version 2.0 11 | */ 12 | public interface PermissionListener { 13 | 14 | void onGranted(); 15 | 16 | void onDenied(List deniedPermissions); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/chaychan/androidnadaption/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.chaychan.androidnadaption.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.ContentValues; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.database.Cursor; 8 | import android.graphics.Bitmap; 9 | import android.net.Uri; 10 | import android.os.Environment; 11 | import android.provider.MediaStore; 12 | 13 | import java.io.File; 14 | import java.io.FileNotFoundException; 15 | import java.io.FileOutputStream; 16 | import java.io.IOException; 17 | 18 | public class FileUtils 19 | { 20 | 21 | public static final String ROOT_DIR = "Android/data/" 22 | + UIUtils.getPackageName(); 23 | public static final String DOWNLOAD_DIR = "download"; 24 | public static final String CACHE_DIR = "cache"; 25 | public static final String ICON_DIR = "icon"; 26 | 27 | public static final String APP_STORAGE_ROOT = "AndroidNAdaption"; 28 | 29 | /** 判断SD卡是否挂载 */ 30 | public static boolean isSDCardAvailable() 31 | { 32 | if (Environment.MEDIA_MOUNTED.equals(Environment 33 | .getExternalStorageState())) 34 | { 35 | return true; 36 | } 37 | else 38 | { 39 | return false; 40 | } 41 | } 42 | 43 | /** 获取下载目录 */ 44 | public static String getDownloadDir() 45 | { 46 | return getDir(DOWNLOAD_DIR); 47 | } 48 | 49 | /** 获取缓存目录 */ 50 | public static String getCacheDir() 51 | { 52 | return getDir(CACHE_DIR); 53 | } 54 | 55 | /** 获取icon目录 */ 56 | public static String getIconDir() 57 | { 58 | return getDir(ICON_DIR); 59 | } 60 | 61 | /** 获取应用目录,当SD卡存在时,获取SD卡上的目录,当SD卡不存在时,获取应用的cache目录 */ 62 | public static String getDir(String name) 63 | { 64 | StringBuilder sb = new StringBuilder(); 65 | if (isSDCardAvailable()) 66 | { 67 | sb.append(getAppExternalStoragePath()); 68 | } 69 | else 70 | { 71 | sb.append(getCachePath()); 72 | } 73 | sb.append(name); 74 | sb.append(File.separator); 75 | String path = sb.toString(); 76 | if (createDirs(path)) 77 | { 78 | return path; 79 | } 80 | else 81 | { 82 | return null; 83 | } 84 | } 85 | 86 | /** 获取SD下的应用目录 */ 87 | public static String getExternalStoragePath() 88 | { 89 | StringBuilder sb = new StringBuilder(); 90 | sb.append(Environment.getExternalStorageDirectory().getAbsolutePath()); 91 | sb.append(File.separator); 92 | sb.append(ROOT_DIR); 93 | sb.append(File.separator); 94 | return sb.toString(); 95 | } 96 | 97 | /** 获取SD下当前APP的目录 */ 98 | public static String getAppExternalStoragePath() 99 | { 100 | StringBuilder sb = new StringBuilder(); 101 | sb.append(Environment.getExternalStorageDirectory().getAbsolutePath()); 102 | sb.append(File.separator); 103 | sb.append(APP_STORAGE_ROOT); 104 | sb.append(File.separator); 105 | return sb.toString(); 106 | } 107 | 108 | /** 获取应用的cache目录 */ 109 | public static String getCachePath() 110 | { 111 | File f = UIUtils.getContext().getCacheDir(); 112 | if (null == f) 113 | { 114 | return null; 115 | } 116 | else 117 | { 118 | return f.getAbsolutePath() + "/"; 119 | } 120 | } 121 | 122 | /** 创建文件夹 */ 123 | public static boolean createDirs(String dirPath) 124 | { 125 | File file = new File(dirPath); 126 | if (!file.exists() || !file.isDirectory()) { return file.mkdirs(); } 127 | return true; 128 | } 129 | 130 | /**产生图片的路径,这里是在缓存目录下*/ 131 | public static String generateImgePathInStoragePath(){ 132 | return getDir(ICON_DIR) + String.valueOf(System.currentTimeMillis()) + ".jpg"; 133 | } 134 | 135 | /** 136 | * 发起剪裁图片的请求 137 | * @param activity 上下文 138 | * @param srcFile 原文件的File 139 | * @param output 输出文件的File 140 | * @param requestCode 请求码 141 | */ 142 | public static void startPhotoZoom(Activity activity, File srcFile, File output,int requestCode) { 143 | Intent intent = new Intent("com.android.camera.action.CROP"); 144 | intent.setDataAndType(getImageContentUri(activity,srcFile), "image/*"); 145 | // crop为true是设置在开启的intent中设置显示的view可以剪裁 146 | intent.putExtra("crop", "true"); 147 | 148 | // aspectX aspectY 是宽高的比例 149 | intent.putExtra("aspectX", 1); 150 | intent.putExtra("aspectY", 1); 151 | 152 | // outputX,outputY 是剪裁图片的宽高 153 | intent.putExtra("outputX", 800); 154 | intent.putExtra("outputY", 480); 155 | // intent.putExtra("return-data", false); 156 | 157 | // intent.putExtra(MediaStore.EXTRA_OUTPUT, 158 | // Uri.fromFile(new File(FileUtils.picPath))); 159 | 160 | intent.putExtra("return-data", false);// true:不返回uri,false:返回uri 161 | intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(output)); 162 | intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); 163 | // intent.putExtra("noFaceDetection", true); // no face detection 164 | 165 | activity.startActivityForResult(intent, requestCode); 166 | } 167 | 168 | /**安卓7.0裁剪根据文件路径获取uri*/ 169 | public static Uri getImageContentUri(Context context, File imageFile) { 170 | String filePath = imageFile.getAbsolutePath(); 171 | Cursor cursor = context.getContentResolver().query( 172 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 173 | new String[] { MediaStore.Images.Media._ID }, 174 | MediaStore.Images.Media.DATA + "=? ", 175 | new String[] { filePath }, null); 176 | 177 | if (cursor != null && cursor.moveToFirst()) { 178 | int id = cursor.getInt(cursor 179 | .getColumnIndex(MediaStore.MediaColumns._ID)); 180 | Uri baseUri = Uri.parse("content://media/external/images/media"); 181 | return Uri.withAppendedPath(baseUri, "" + id); 182 | } else { 183 | if (imageFile.exists()) { 184 | ContentValues values = new ContentValues(); 185 | values.put(MediaStore.Images.Media.DATA, filePath); 186 | return context.getContentResolver().insert( 187 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); 188 | } else { 189 | return null; 190 | } 191 | } 192 | } 193 | 194 | /** 195 | * 复制bm 196 | * @param bm 197 | * @return 198 | */ 199 | public static String saveBitmap(Bitmap bm) { 200 | String croppath=""; 201 | try { 202 | File f = new File(FileUtils.generateImgePathInStoragePath()); 203 | //得到相机图片存到本地的图片 204 | croppath=f.getPath(); 205 | if (f.exists()) { 206 | f.delete(); 207 | } 208 | FileOutputStream out = new FileOutputStream(f); 209 | bm.compress(Bitmap.CompressFormat.JPEG, 100, out); 210 | out.flush(); 211 | out.close(); 212 | } catch (FileNotFoundException e) { 213 | e.printStackTrace(); 214 | } catch (IOException e) { 215 | e.printStackTrace(); 216 | } 217 | return croppath; 218 | } 219 | 220 | /** 221 | * 按质量压缩bm 222 | * @param bm 223 | * @param quality 压缩率 224 | * @return 225 | */ 226 | public static String saveBitmapByQuality(Bitmap bm,int quality) { 227 | String croppath=""; 228 | try { 229 | File f = new File(FileUtils.generateImgePathInStoragePath()); 230 | //得到相机图片存到本地的图片 231 | croppath=f.getPath(); 232 | if (f.exists()) { 233 | f.delete(); 234 | } 235 | FileOutputStream out = new FileOutputStream(f); 236 | bm.compress(Bitmap.CompressFormat.JPEG,quality, out); 237 | out.flush(); 238 | out.close(); 239 | } catch (FileNotFoundException e) { 240 | e.printStackTrace(); 241 | } catch (IOException e) { 242 | e.printStackTrace(); 243 | } 244 | return croppath; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /app/src/main/java/com/chaychan/androidnadaption/utils/ImageTools.java: -------------------------------------------------------------------------------- 1 | package com.chaychan.androidnadaption.utils; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Bitmap.Config; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.LinearGradient; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.PixelFormat; 11 | import android.graphics.PorterDuff.Mode; 12 | import android.graphics.PorterDuffXfermode; 13 | import android.graphics.Rect; 14 | import android.graphics.RectF; 15 | import android.graphics.Shader.TileMode; 16 | import android.graphics.drawable.BitmapDrawable; 17 | import android.graphics.drawable.Drawable; 18 | import android.net.Uri; 19 | 20 | import java.io.ByteArrayInputStream; 21 | import java.io.ByteArrayOutputStream; 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.FileNotFoundException; 25 | import java.io.FileOutputStream; 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | import java.nio.channels.FileChannel; 29 | 30 | /** 31 | * Tools for handler picture 32 | * 33 | * @author Ryan.Tang 34 | * 35 | */ 36 | public final class ImageTools { 37 | 38 | /** 39 | * Transfer drawable to bitmap 40 | * 41 | * @param drawable 42 | * @return 43 | */ 44 | public static Bitmap drawableToBitmap(Drawable drawable) { 45 | int w = drawable.getIntrinsicWidth(); 46 | int h = drawable.getIntrinsicHeight(); 47 | 48 | Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Config.ARGB_8888 49 | : Config.RGB_565; 50 | Bitmap bitmap = Bitmap.createBitmap(w, h, config); 51 | Canvas canvas = new Canvas(bitmap); 52 | drawable.setBounds(0, 0, w, h); 53 | drawable.draw(canvas); 54 | return bitmap; 55 | } 56 | 57 | /** 58 | * Bitmap to drawable 59 | * 60 | * @param bitmap 61 | * @return 62 | */ 63 | public static Drawable bitmapToDrawable(Bitmap bitmap) { 64 | return new BitmapDrawable(bitmap); 65 | } 66 | 67 | /** 68 | * Input stream to bitmap 69 | * 70 | * @param inputStream 71 | * @return 72 | * @throws Exception 73 | */ 74 | public static Bitmap inputStreamToBitmap(InputStream inputStream) 75 | throws Exception { 76 | return BitmapFactory.decodeStream(inputStream); 77 | } 78 | 79 | /** 80 | * Byte transfer to bitmap 81 | * 82 | * @param byteArray 83 | * @return 84 | */ 85 | public static Bitmap byteToBitmap(byte[] byteArray) { 86 | if (byteArray.length != 0) { 87 | return BitmapFactory 88 | .decodeByteArray(byteArray, 0, byteArray.length); 89 | } else { 90 | return null; 91 | } 92 | } 93 | 94 | /** 95 | * Byte transfer to drawable 96 | * 97 | * @param byteArray 98 | * @return 99 | */ 100 | public static Drawable byteToDrawable(byte[] byteArray) { 101 | ByteArrayInputStream ins = null; 102 | if (byteArray != null) { 103 | ins = new ByteArrayInputStream(byteArray); 104 | } 105 | return Drawable.createFromStream(ins, null); 106 | } 107 | 108 | /** 109 | * Bitmap transfer to bytes 110 | * 111 | * @return 112 | */ 113 | public static byte[] bitmapToBytes(Bitmap bm) { 114 | byte[] bytes = null; 115 | if (bm != null) { 116 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 117 | bm.compress(Bitmap.CompressFormat.PNG, 100, baos); 118 | bytes = baos.toByteArray(); 119 | } 120 | return bytes; 121 | } 122 | 123 | /** 124 | * Drawable transfer to bytes 125 | * 126 | * @param drawable 127 | * @return 128 | */ 129 | public static byte[] drawableToBytes(Drawable drawable) { 130 | BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; 131 | Bitmap bitmap = bitmapDrawable.getBitmap(); 132 | byte[] bytes = bitmapToBytes(bitmap); 133 | ; 134 | return bytes; 135 | } 136 | 137 | /** 138 | * Base64 to byte[] 139 | // */ 140 | // public static byte[] base64ToBytes(String base64) throws IOException { 141 | // byte[] bytes = Base64.decode(base64); 142 | // return bytes; 143 | // } 144 | // 145 | // /** 146 | // * Byte[] to base64 147 | // */ 148 | // public static String bytesTobase64(byte[] bytes) { 149 | // String base64 = Base64.encode(bytes); 150 | // return base64; 151 | // } 152 | 153 | /** 154 | * Create reflection images 155 | * 156 | * @param bitmap 157 | * @return 158 | */ 159 | public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) { 160 | final int reflectionGap = 4; 161 | int w = bitmap.getWidth(); 162 | int h = bitmap.getHeight(); 163 | 164 | Matrix matrix = new Matrix(); 165 | matrix.preScale(1, -1); 166 | 167 | Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w, 168 | h / 2, matrix, false); 169 | 170 | Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2), 171 | Config.ARGB_8888); 172 | 173 | Canvas canvas = new Canvas(bitmapWithReflection); 174 | canvas.drawBitmap(bitmap, 0, 0, null); 175 | Paint deafalutPaint = new Paint(); 176 | canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint); 177 | 178 | canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null); 179 | 180 | Paint paint = new Paint(); 181 | LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, 182 | bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 183 | 0x00ffffff, TileMode.CLAMP); 184 | paint.setShader(shader); 185 | // Set the Transfer mode to be porter duff and destination in 186 | paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 187 | // Draw a rectangle using the paint with our linear gradient 188 | canvas.drawRect(0, h, w, bitmapWithReflection.getHeight() 189 | + reflectionGap, paint); 190 | 191 | return bitmapWithReflection; 192 | } 193 | 194 | /** 195 | * Get rounded corner images 196 | * 197 | * @param bitmap 198 | * @param roundPx 199 | * 5 10 200 | * @return 201 | */ 202 | public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { 203 | int w = bitmap.getWidth(); 204 | int h = bitmap.getHeight(); 205 | Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); 206 | Canvas canvas = new Canvas(output); 207 | final int color = 0xff424242; 208 | final Paint paint = new Paint(); 209 | final Rect rect = new Rect(0, 0, w, h); 210 | final RectF rectF = new RectF(rect); 211 | paint.setAntiAlias(true); 212 | canvas.drawARGB(0, 0, 0, 0); 213 | paint.setColor(color); 214 | canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 215 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 216 | canvas.drawBitmap(bitmap, rect, rect, paint); 217 | 218 | return output; 219 | } 220 | 221 | /** 222 | * Resize the bitmap 223 | * 224 | * @param bitmap 225 | * @param width 226 | * @param height 227 | * @return 228 | */ 229 | public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { 230 | int w = bitmap.getWidth(); 231 | int h = bitmap.getHeight(); 232 | Matrix matrix = new Matrix(); 233 | float scaleWidth = ((float) width / w); 234 | float scaleHeight = ((float) height / h); 235 | matrix.postScale(scaleWidth, scaleHeight); 236 | Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); 237 | return newbmp; 238 | } 239 | 240 | /** 241 | * Resize the drawable 242 | * @param drawable 243 | * @param w 244 | * @param h 245 | * @return 246 | */ 247 | public static Drawable zoomDrawable(Drawable drawable, int w, int h) { 248 | int width = drawable.getIntrinsicWidth(); 249 | int height = drawable.getIntrinsicHeight(); 250 | Bitmap oldbmp = drawableToBitmap(drawable); 251 | Matrix matrix = new Matrix(); 252 | float sx = ((float) w / width); 253 | float sy = ((float) h / height); 254 | matrix.postScale(sx, sy); 255 | Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, 256 | matrix, true); 257 | return new BitmapDrawable(newbmp); 258 | } 259 | 260 | /** 261 | * Get images from SD card by path and the name of image 262 | * @param photoName 263 | * @return 264 | */ 265 | public static Bitmap getPhotoFromSDCard(String path,String photoName){ 266 | Bitmap photoBitmap = BitmapFactory.decodeFile(path + "/" +photoName +".png"); 267 | if (photoBitmap == null) { 268 | return null; 269 | }else { 270 | return photoBitmap; 271 | } 272 | } 273 | 274 | /** 275 | * Check the SD card 276 | * @return 277 | */ 278 | public static boolean checkSDCardAvailable(){ 279 | return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); 280 | } 281 | 282 | /** 283 | * Get image from SD card by path and the name of image 284 | * @return 285 | */ 286 | public static boolean findPhotoFromSDCard(String path,String photoName){ 287 | boolean flag = false; 288 | 289 | if (checkSDCardAvailable()) { 290 | File dir = new File(path); 291 | if (dir.exists()) { 292 | File folders = new File(path); 293 | File photoFile[] = folders.listFiles(); 294 | for (int i = 0; i < photoFile.length; i++) { 295 | String fileName = photoFile[i].getName().split("\\.")[0]; 296 | if (fileName.equals(photoName)) { 297 | flag = true; 298 | } 299 | } 300 | }else { 301 | flag = false; 302 | } 303 | // File file = new File(path + "/" + photoName + ".jpg" ); 304 | // if (file.exists()) { 305 | // flag = true; 306 | // }else { 307 | // flag = false; 308 | // } 309 | 310 | }else { 311 | flag = false; 312 | } 313 | return flag; 314 | } 315 | 316 | /** 317 | * Save image to the SD card 318 | * @param photoBitmap 319 | * @param photoName 320 | * @param path 321 | */ 322 | public static void savePhotoToSDCard(Bitmap photoBitmap,String path,String photoName){ 323 | if (checkSDCardAvailable()) { 324 | File dir = new File(path); 325 | if (!dir.exists()){ 326 | dir.mkdirs(); 327 | } 328 | 329 | File photoFile = new File(path , photoName + ".png"); 330 | FileOutputStream fileOutputStream = null; 331 | try { 332 | fileOutputStream = new FileOutputStream(photoFile); 333 | if (photoBitmap != null) { 334 | if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) { 335 | fileOutputStream.flush(); 336 | // fileOutputStream.close(); 337 | } 338 | } 339 | } catch (FileNotFoundException e) { 340 | photoFile.delete(); 341 | e.printStackTrace(); 342 | } catch (IOException e) { 343 | photoFile.delete(); 344 | e.printStackTrace(); 345 | } finally{ 346 | try { 347 | fileOutputStream.close(); 348 | } catch (IOException e) { 349 | e.printStackTrace(); 350 | } 351 | } 352 | } 353 | } 354 | 355 | /** 356 | * Delete the image from SD card 357 | * @param path 358 | * file:///sdcard/temp.jpg 359 | */ 360 | public static void deleteAllPhoto(String path){ 361 | if (checkSDCardAvailable()) { 362 | File folder = new File(path); 363 | File[] files = folder.listFiles(); 364 | for (int i = 0; i < files.length; i++) { 365 | files[i].delete(); 366 | } 367 | } 368 | } 369 | 370 | public static void deletePhotoAtPathAndName(String path,String fileName){ 371 | if (checkSDCardAvailable()) { 372 | File folder = new File(path); 373 | File[] files = folder.listFiles(); 374 | for (int i = 0; i < files.length; i++) { 375 | if (files[i].getName().split("\\.")[0].equals(fileName)) { 376 | files[i].delete(); 377 | } 378 | } 379 | } 380 | } 381 | 382 | public static Bitmap compressBitmap(Bitmap image) { 383 | 384 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 385 | image.compress(Bitmap.CompressFormat.JPEG, 100, baos); 386 | if( baos.toByteArray().length / 1024>1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出 387 | baos.reset();//重置baos即清空baos 388 | image.compress(Bitmap.CompressFormat.JPEG, 50, baos);//这里压缩50%,把压缩后的数据存放到baos中 389 | } 390 | ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); 391 | BitmapFactory.Options newOpts = new BitmapFactory.Options(); 392 | //开始读入图片,此时把options.inJustDecodeBounds 设回true了 393 | newOpts.inJustDecodeBounds = true; 394 | Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); 395 | newOpts.inJustDecodeBounds = false; 396 | int w = newOpts.outWidth; 397 | int h = newOpts.outHeight; 398 | //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为 399 | float hh = 800f;//这里设置高度为800f 400 | float ww = 480f;//这里设置宽度为480f 401 | //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 402 | int be = 1;//be=1表示不缩放 403 | if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 404 | be = (int) (newOpts.outWidth / ww); 405 | } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 406 | be = (int) (newOpts.outHeight / hh); 407 | } 408 | if (be <= 0) 409 | be = 1; 410 | newOpts.inSampleSize = be;//设置缩放比例 411 | //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 412 | isBm = new ByteArrayInputStream(baos.toByteArray()); 413 | bitmap = BitmapFactory.decodeStream(isBm, null, newOpts); 414 | return compressImage(bitmap);//压缩好比例大小后再进行质量压缩 415 | } 416 | 417 | 418 | private static Bitmap compressImage(Bitmap image) { 419 | 420 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 421 | image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 422 | int options = 100; 423 | while ( baos.toByteArray().length / 1024>100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩 424 | baos.reset();//重置baos即清空baos 425 | image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中 426 | options -= 10;//每次都减少10 427 | } 428 | ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中 429 | Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片 430 | return bitmap; 431 | } 432 | 433 | public static Bitmap getImageFromPath(String srcPath) { 434 | BitmapFactory.Options newOpts = new BitmapFactory.Options(); 435 | //开始读入图片,此时把options.inJustDecodeBounds 设回true了 436 | newOpts.inJustDecodeBounds = true; 437 | Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//此时返回bm为空 438 | 439 | newOpts.inJustDecodeBounds = false; 440 | int w = newOpts.outWidth; 441 | int h = newOpts.outHeight; 442 | //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为 443 | float hh = 800f;//这里设置高度为800f 444 | float ww = 480f;//这里设置宽度为480f 445 | //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 446 | int be = 1;//be=1表示不缩放 447 | if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 448 | be = (int) (newOpts.outWidth / ww); 449 | } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 450 | be = (int) (newOpts.outHeight / hh); 451 | } 452 | if (be <= 0) 453 | be = 1; 454 | newOpts.inSampleSize = be;//设置缩放比例 455 | //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 456 | bitmap = BitmapFactory.decodeFile(srcPath, newOpts); 457 | return compressImage(bitmap);//压缩好比例大小后再进行质量压缩 458 | } 459 | 460 | /** 461 | * 压缩图片文件 462 | * @param path 文件的路径 463 | * @return 464 | */ 465 | public static File scaleImageFile(String path){ 466 | File outputFile = new File(path); 467 | long fileSize = outputFile.length(); 468 | final long fileMaxSize = 200 * 1024; 469 | if (fileSize >= fileMaxSize) { 470 | BitmapFactory.Options options = new BitmapFactory.Options(); 471 | options.inJustDecodeBounds = true; 472 | BitmapFactory.decodeFile(path, options); 473 | int height = options.outHeight; 474 | int width = options.outWidth; 475 | 476 | double scale = Math.sqrt((float) fileSize / fileMaxSize); 477 | options.outHeight = (int) (height / scale); 478 | options.outWidth = (int) (width / scale); 479 | options.inSampleSize = (int) (scale + 0.5); 480 | options.inJustDecodeBounds = false; 481 | 482 | Bitmap bitmap = BitmapFactory.decodeFile(path, options); 483 | outputFile = new File(createImageFile().getPath()); 484 | FileOutputStream fos = null; 485 | try { 486 | fos = new FileOutputStream(outputFile); 487 | bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos); 488 | fos.close(); 489 | } catch (IOException e) { 490 | // TODO Auto-generated catch block 491 | e.printStackTrace(); 492 | } 493 | if (!bitmap.isRecycled()) { 494 | bitmap.recycle(); 495 | }else{ 496 | File tempFile = outputFile; 497 | outputFile = new File(createImageFile().getPath()); 498 | copyFileUsingFileChannels(tempFile, outputFile,true); 499 | } 500 | } 501 | return outputFile; 502 | } 503 | 504 | 505 | public static Uri createImageFile(){ 506 | String prefix = String.valueOf(System.currentTimeMillis()); 507 | File image = null; 508 | try { 509 | image = File.createTempFile( 510 | prefix, /* prefix */ 511 | ".jpg", /* suffix */ 512 | new File(FileUtils.getDir(FileUtils.ICON_DIR)) /* directory */ 513 | ); 514 | } catch (IOException e) { 515 | e.printStackTrace(); 516 | } 517 | return Uri.fromFile(image); 518 | } 519 | 520 | 521 | public static boolean copyFileUsingFileChannels(File source, File dest,boolean shouldDelete){ 522 | FileChannel inputChannel = null; 523 | FileChannel outputChannel = null; 524 | try { 525 | try { 526 | inputChannel = new FileInputStream(source).getChannel(); 527 | outputChannel = new FileOutputStream(dest).getChannel(); 528 | outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); 529 | if(shouldDelete){ 530 | //如果需要删除源文件 531 | if (source.exists()){ 532 | source.delete(); 533 | } 534 | } 535 | } catch (IOException e) { 536 | e.printStackTrace(); 537 | return false; 538 | } 539 | } finally { 540 | try { 541 | inputChannel.close(); 542 | outputChannel.close(); 543 | } catch (IOException e) { 544 | e.printStackTrace(); 545 | return false; 546 | } 547 | } 548 | 549 | return true; 550 | } 551 | 552 | public static Bitmap decodeUriAsBitmap(Uri uri) { 553 | Bitmap bitmap = null; 554 | try { 555 | // 先通过getContentResolver方法获得一个ContentResolver实例, 556 | // 调用openInputStream(Uri)方法获得uri关联的数据流stream 557 | // 把上一步获得的数据流解析成为bitmap 558 | bitmap = BitmapFactory.decodeStream(UIUtils.getContext().getContentResolver().openInputStream(uri)); 559 | } catch (FileNotFoundException e) { 560 | e.printStackTrace(); 561 | return null; 562 | } 563 | return bitmap; 564 | } 565 | 566 | } -------------------------------------------------------------------------------- /app/src/main/java/com/chaychan/androidnadaption/utils/UIUtils.java: -------------------------------------------------------------------------------- 1 | package com.chaychan.androidnadaption.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.os.Handler; 6 | import android.util.DisplayMetrics; 7 | import android.view.View; 8 | import android.view.WindowManager; 9 | import android.view.inputmethod.InputMethodManager; 10 | import android.widget.Toast; 11 | 12 | import com.chaychan.androidnadaption.MyApplication; 13 | 14 | 15 | /** 16 | * 和ui相关的工具类 17 | */ 18 | public class UIUtils { 19 | 20 | public static Toast mToast; 21 | 22 | public static void showToast(String msg) { 23 | if (mToast == null) { 24 | mToast = Toast.makeText(UIUtils.getContext(), "", Toast.LENGTH_SHORT); 25 | } 26 | mToast.setText(msg); 27 | mToast.show(); 28 | } 29 | 30 | public static void showToastSafely(final String msg) { 31 | UIUtils.postTaskSafely(new Runnable() { 32 | @Override 33 | public void run() { 34 | showToast(msg); 35 | } 36 | }); 37 | } 38 | 39 | 40 | /** 41 | * 用于在线程中执行弹土司操作 42 | */ 43 | public static void showToastSafely(final Context mContext, final String msg) { 44 | UIUtils.getMainThreadHandler().post(new Runnable() { 45 | 46 | @Override 47 | public void run() { 48 | if (mToast == null) { 49 | mToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT); 50 | } 51 | mToast.setText(msg); 52 | mToast.show(); 53 | } 54 | }); 55 | } 56 | 57 | 58 | /** 59 | * 得到上下文 60 | * 61 | * @return 62 | */ 63 | public static Context getContext() { 64 | return MyApplication.getContext(); 65 | } 66 | 67 | /** 68 | * 得到resources对象 69 | * 70 | * @return 71 | */ 72 | public static Resources getResource() { 73 | return getContext().getResources(); 74 | } 75 | 76 | /** 77 | * 得到string.xml中的字符串 78 | * 79 | * @param resId 80 | * @return 81 | */ 82 | public static String getString(int resId) { 83 | return getResource().getString(resId); 84 | } 85 | 86 | /** 87 | * 得到string.xml中的字符串,带点位符 88 | */ 89 | public static String getString(int id, Object... formatArgs) { 90 | return getResource().getString(id, formatArgs); 91 | } 92 | 93 | /** 94 | * 得到string.xml中和字符串数组 95 | * 96 | * @param resId 97 | * @return 98 | */ 99 | public static String[] getStringArr(int resId) { 100 | return getResource().getStringArray(resId); 101 | } 102 | 103 | /** 104 | * 得到colors.xml中的颜色 105 | * 106 | * @param colorId 107 | * @return 108 | */ 109 | public static int getColor(int colorId) { 110 | return getResource().getColor(colorId); 111 | } 112 | 113 | /** 114 | * 得到应用程序的包名 115 | * 116 | * @return 117 | */ 118 | public static String getPackageName() { 119 | return getContext().getPackageName(); 120 | } 121 | 122 | /** 123 | * 得到主线程Handler 124 | * 125 | * @return 126 | */ 127 | public static Handler getMainThreadHandler() { 128 | return MyApplication.getHandler(); 129 | } 130 | 131 | /** 132 | * 得到主线程id 133 | * 134 | * @return 135 | */ 136 | public static long getMainThreadId() { 137 | return MyApplication.getMainThreadId(); 138 | } 139 | 140 | /** 141 | * 安全的执行一个任务 142 | * 143 | * @param task 144 | */ 145 | public static void postTaskSafely(Runnable task) { 146 | int curThreadId = android.os.Process.myTid(); 147 | // 如果当前线程是主线程 148 | if (curThreadId == getMainThreadId()) { 149 | task.run(); 150 | } else { 151 | // 如果当前线程不是主线程 152 | getMainThreadHandler().post(task); 153 | } 154 | } 155 | 156 | /** 157 | * 延迟执行任务 158 | * 159 | * @param task 160 | * @param delayMillis 161 | */ 162 | public static void postTaskDelay(Runnable task, int delayMillis) { 163 | getMainThreadHandler().postDelayed(task, delayMillis); 164 | } 165 | 166 | /** 167 | * 移除任务 168 | */ 169 | public static void removeTask(Runnable task) { 170 | getMainThreadHandler().removeCallbacks(task); 171 | } 172 | 173 | /** 174 | * dip-->px 175 | */ 176 | public static int dip2Px(int dip) { 177 | // px/dip = density; 178 | // density = dpi/160 179 | // 320*480 density = 1 1px = 1dp 180 | // 1280*720 density = 2 2px = 1dp 181 | 182 | float density = getResource().getDisplayMetrics().density; 183 | int px = (int) (dip * density + 0.5f); 184 | return px; 185 | } 186 | 187 | /** 188 | * px-->dip 189 | */ 190 | public static int px2dip(int px) { 191 | 192 | float density = getResource().getDisplayMetrics().density; 193 | int dip = (int) (px / density + 0.5f); 194 | return dip; 195 | } 196 | 197 | /**收起软键盘*/ 198 | public static void hideInput(View view){ 199 | InputMethodManager imm = (InputMethodManager) UIUtils.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 200 | imm.hideSoftInputFromWindow(view.getWindowToken(), 0) ; 201 | } 202 | 203 | public static void showInput(View view){ 204 | InputMethodManager imm = (InputMethodManager) UIUtils.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 205 | imm.showSoftInput(view,0); 206 | } 207 | 208 | /**获取屏幕高度*/ 209 | public static int getScreenHeight(){ 210 | DisplayMetrics dm = new DisplayMetrics(); 211 | //取得窗口属性 212 | WindowManager wm = (WindowManager) UIUtils.getContext().getSystemService(Context.WINDOW_SERVICE); 213 | wm.getDefaultDisplay().getMetrics(dm); 214 | 215 | //窗口的宽度 216 | return dm.heightPixels; 217 | } 218 | 219 | /**获取屏幕宽度*/ 220 | public static int getScreenWidth(){ 221 | DisplayMetrics dm = new DisplayMetrics(); 222 | //取得窗口属性 223 | WindowManager wm = (WindowManager) UIUtils.getContext().getSystemService(Context.WINDOW_SERVICE); 224 | wm.getDefaultDisplay().getMetrics(dm); 225 | 226 | //窗口的宽度 227 | return dm.widthPixels; 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 15 | 16 | 24 | 25 |