├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wuwang │ │ └── app │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wuwang │ │ │ └── app │ │ │ ├── ExampleCropPath.java │ │ │ ├── MainActivity.java │ │ │ └── ShowAdapter.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ └── item_image.xml │ │ ├── menu │ │ └── item_menu.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 │ └── test │ └── java │ └── com │ └── wuwang │ └── app │ └── ExampleUnitTest.java ├── build.gradle ├── chooser ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wuwang │ │ └── imagechooser │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wuwang │ │ │ ├── imagechooser │ │ │ ├── ChooserSetting.java │ │ │ ├── EntryActivity.java │ │ │ ├── IcFinal.java │ │ │ ├── abslayer │ │ │ │ ├── IAlpha.java │ │ │ │ ├── IImageClickListener.java │ │ │ │ └── IPhotoShoot.java │ │ │ ├── album │ │ │ │ ├── AbsAlbumEntry.java │ │ │ │ ├── AlbumAdapter.java │ │ │ │ ├── AlbumEntry.java │ │ │ │ ├── AlbumPopup.java │ │ │ │ ├── AlbumTool.java │ │ │ │ ├── AlbumVar.java │ │ │ │ ├── FolderAdapter.java │ │ │ │ ├── FolderFragment.java │ │ │ │ ├── IAlbumClickListener.java │ │ │ │ ├── ImageFolder.java │ │ │ │ └── ImageInfo.java │ │ │ ├── crop │ │ │ │ ├── ACropCoverDrawable.java │ │ │ │ ├── CropActivity.java │ │ │ │ ├── CropCoverDrawable.java │ │ │ │ ├── CropFragment.java │ │ │ │ ├── CropHelper.java │ │ │ │ └── CropPath.java │ │ │ └── res │ │ │ │ ├── CircleChooseDrawable.java │ │ │ │ └── IChooseDrawable.java │ │ │ ├── utils │ │ │ ├── DensityUtils.java │ │ │ └── LogUtils.java │ │ │ └── widget │ │ │ ├── SquareImageView.java │ │ │ └── SquareRelativeLayout.java │ └── res │ │ ├── drawable │ │ ├── image_chooser_folder_item_bg.xml │ │ └── left_back.xml │ │ ├── layout │ │ ├── image_chooser_activity_crop.xml │ │ ├── image_chooser_activity_entry.xml │ │ ├── image_chooser_default_title.xml │ │ ├── image_chooser_fragment_album.xml │ │ ├── image_chooser_fragment_crop.xml │ │ ├── image_chooser_fragment_folder.xml │ │ ├── image_chooser_item_album.xml │ │ ├── image_chooser_item_camera.xml │ │ └── image_chooser_item_image.xml │ │ ├── menu │ │ ├── menu_album.xml │ │ └── menu_crop.xml │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── image_chooser_back.png │ │ ├── image_chooser_camera.png │ │ ├── image_chooser_down.png │ │ └── image_chooser_placeholder.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── wuwang │ └── imagechooser │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.md └── 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 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.1" 6 | defaultConfig { 7 | applicationId "com.wuwang.app" 8 | minSdkVersion 9 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 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(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | testCompile 'junit:junit:4.12' 28 | compile project(':chooser') 29 | } 30 | -------------------------------------------------------------------------------- /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 C:\Android\android-sdk/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/wuwang/app/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.app; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.wuwang.app", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/wuwang/app/ExampleCropPath.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.app; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.ColorFilter; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.graphics.PixelFormat; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuffXfermode; 11 | import android.graphics.Rect; 12 | import android.os.Build; 13 | 14 | import com.wuwang.imagechooser.crop.ACropCoverDrawable; 15 | 16 | /** 17 | * Created by wuwang on 2016/11/13 18 | */ 19 | 20 | public class ExampleCropPath extends ACropCoverDrawable{ 21 | 22 | Paint paint; 23 | private Rect rect; 24 | private Path cropPath; 25 | 26 | public ExampleCropPath(int param){ 27 | super(0); 28 | paint=new Paint(); 29 | paint.setAntiAlias(true); 30 | paint.setColor(0x88000000); 31 | } 32 | 33 | @Override 34 | public void draw(Canvas canvas) { 35 | int cWidth=canvas.getWidth(); 36 | int cHeight=canvas.getHeight(); 37 | if(rect==null){ 38 | rect=new Rect(cWidth/6,cHeight/2-cWidth/3,cWidth*5/6,cHeight/2+cWidth/3); 39 | } 40 | canvas.drawColor(Color.TRANSPARENT); 41 | Path path=new Path(); 42 | path.addRect(0,0,cWidth,cHeight, Path.Direction.CW); 43 | cropPath=new Path(); 44 | cropPath.moveTo(rect.left,rect.top+rect.height()/4); 45 | cropPath.lineTo(rect.left+rect.width()/4,rect.top); 46 | cropPath.lineTo(rect.right-rect.width()/4,rect.top); 47 | cropPath.lineTo(rect.right,rect.top+rect.height()/4); 48 | cropPath.lineTo(rect.right,rect.centerY()); 49 | cropPath.quadTo(rect.right,rect.bottom,rect.centerX(),rect.bottom); 50 | cropPath.quadTo(rect.left,rect.bottom,rect.left,rect.centerY()); 51 | cropPath.close(); 52 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 53 | path.op(cropPath, Path.Op.DIFFERENCE); //可以抗锯齿 54 | canvas.drawPath(path,paint); 55 | }else{ 56 | //此方法可以去掉锯齿 57 | //在这里saveLayer然后restoreToCount的操作不能少,否则不会得到想要的效果 58 | int layerId = canvas.saveLayer(0, 0, cWidth, cHeight, null, Canvas.ALL_SAVE_FLAG); 59 | canvas.drawPath(path,paint); 60 | //已经绘制的可以看做为目标图 61 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 62 | canvas.drawPath(cropPath,paint); 63 | paint.setXfermode(null); 64 | canvas.restoreToCount(layerId); 65 | //裁剪的方式会有锯齿,没找到方法去掉锯齿 66 | //canvas.clipPath(opPath, Region.Op.DIFFERENCE); 67 | //canvas.drawRect(0,0,cWidth,cHeight,paint); 68 | } 69 | } 70 | 71 | @Override 72 | public void setAlpha(int alpha) { 73 | paint.setAlpha(alpha); 74 | } 75 | 76 | @Override 77 | public void setColorFilter(ColorFilter colorFilter) { 78 | paint.setColorFilter(colorFilter); 79 | } 80 | 81 | @Override 82 | public int getOpacity() { 83 | return PixelFormat.TRANSPARENT; 84 | } 85 | 86 | @Override 87 | public Rect limit() { 88 | return rect; 89 | } 90 | 91 | @Override 92 | public Path path() { 93 | return cropPath; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/wuwang/app/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.app; 2 | 3 | import android.content.Intent; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | import android.widget.GridView; 10 | 11 | import com.wuwang.imagechooser.EntryActivity; 12 | import com.wuwang.imagechooser.IcFinal; 13 | import com.wuwang.imagechooser.crop.CropPath; 14 | import com.wuwang.utils.LogUtils; 15 | 16 | public class MainActivity extends AppCompatActivity { 17 | 18 | private GridView mGrid; 19 | private ShowAdapter adapter; 20 | private boolean flag; //多选flag 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | mGrid= (GridView) findViewById(R.id.mGrid); 27 | mGrid.setAdapter(adapter=new ShowAdapter()); 28 | } 29 | 30 | @Override 31 | public boolean onCreateOptionsMenu(Menu menu) { 32 | getMenuInflater().inflate(R.menu.item_menu,menu); 33 | return super.onCreateOptionsMenu(menu); 34 | } 35 | 36 | @Override 37 | public boolean onOptionsItemSelected(MenuItem item) { 38 | flag=false; 39 | Intent intent=new Intent(IcFinal.ACTION_ALBUM); 40 | switch (item.getItemId()){ 41 | case R.id.mOne: 42 | intent.putExtra(IcFinal.INTENT_MAX_IMG,1); 43 | break; 44 | case R.id.mNine: 45 | intent.putExtra(IcFinal.INTENT_MAX_IMG,9); 46 | if(flag){ 47 | intent.putStringArrayListExtra(IcFinal.INTENT_EXIST_DATA,adapter.data); 48 | } 49 | flag=true; 50 | break; 51 | case R.id.mCrop: 52 | intent.putExtra(IcFinal.INTENT_IS_CROP,true); 53 | intent.putExtra(IcFinal.INTENT_CROP_SHAPE, CropPath.SHAPE_CIRCLE); 54 | intent.putExtra(IcFinal.INTENT_CROP_WIDTH,500); 55 | intent.putExtra(IcFinal.INTENT_CROP_HEIGHT,500); 56 | break; 57 | case R.id.mCrop2: 58 | intent.putExtra(IcFinal.INTENT_IS_CROP,true); 59 | intent.putExtra(IcFinal.INTENT_CROP_SHAPE, CropPath.SHAPE_RECT); 60 | intent.putExtra(IcFinal.INTENT_CROP_WIDTH,500); 61 | intent.putExtra(IcFinal.INTENT_CROP_HEIGHT,500); 62 | break; 63 | case R.id.mCrop3: 64 | LogUtils.e("wuwang",ExampleCropPath.class.getName()); 65 | intent.putExtra(IcFinal.INTENT_IS_CROP,true); 66 | intent.putExtra(IcFinal.INTENT_CROP_COVER,ExampleCropPath.class.getName()); 67 | intent.putExtra(IcFinal.INTENT_CROP_PARAM,1); 68 | break; 69 | } 70 | startActivityForResult(intent,1); 71 | return super.onOptionsItemSelected(item); 72 | } 73 | 74 | @Override 75 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 76 | super.onActivityResult(requestCode, resultCode, data); 77 | if(resultCode==RESULT_OK){ 78 | adapter.data.clear(); 79 | adapter.data.addAll(data.getStringArrayListExtra(IcFinal.RESULT_DATA_IMG)); 80 | adapter.notifyDataSetChanged(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/wuwang/app/ShowAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.app; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.BaseAdapter; 7 | import android.widget.ImageView; 8 | 9 | import com.bumptech.glide.Glide; 10 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by wuwang on 2016/11/4 17 | */ 18 | 19 | public class ShowAdapter extends BaseAdapter { 20 | 21 | public ArrayList data=new ArrayList<>(); 22 | 23 | public ShowAdapter(){ 24 | } 25 | 26 | @Override 27 | public int getCount() { 28 | return data.size(); 29 | } 30 | 31 | @Override 32 | public Object getItem(int position) { 33 | return data.get(position); 34 | } 35 | 36 | @Override 37 | public long getItemId(int position) { 38 | return position; 39 | } 40 | 41 | @Override 42 | public View getView(int position, View convertView, ViewGroup parent) { 43 | if(convertView==null){ 44 | convertView= LayoutInflater.from(parent.getContext()).inflate(R.layout.image_chooser_item_image,parent,false); 45 | ImageView iv= (ImageView) convertView.findViewById(R.id.mImage); 46 | Glide.with(parent.getContext()).load(data.get(position)).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE).into(iv); 47 | convertView.setTag(iv); 48 | }else{ 49 | Glide.with(parent.getContext()).load(data.get(position)).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.NONE).into((ImageView) convertView.getTag()); 50 | } 51 | return convertView; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/item_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 11 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #0dc6e2 4 | #0dc6e2 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ImageChooser 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/wuwang/app/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.app; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /chooser/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /chooser/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 9 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(include: ['*.jar'], dir: 'libs') 25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | compile 'com.android.support:appcompat-v7:24.2.0' 29 | testCompile 'junit:junit:4.12' 30 | compile 'com.github.bumptech.glide:glide:3.7.0' 31 | } 32 | -------------------------------------------------------------------------------- /chooser/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 C:\Android\android-sdk/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 | -------------------------------------------------------------------------------- /chooser/src/androidTest/java/com/wuwang/imagechooser/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.wuwang.imagechooser.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chooser/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/ChooserSetting.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser; 2 | 3 | 4 | import android.os.Environment; 5 | 6 | import com.wuwang.imagechooser.res.CircleChooseDrawable; 7 | import com.wuwang.imagechooser.res.IChooseDrawable; 8 | 9 | /** 10 | * Description: 11 | */ 12 | public class ChooserSetting{ 13 | 14 | 15 | public static final int TP_SYSTEM=0; 16 | public static final int TP_CUSTOM=1; 17 | public static final int TP_NONE=2; 18 | 19 | /**标题的背景颜色*/ 20 | public static int TITLE_COLOR=0xFF0dc6e2; 21 | 22 | /**图片选择页,每行显示数*/ 23 | public static int NUM_COLUMNS=3; 24 | 25 | /**图片加载失败的图片*/ 26 | public static int errorResId=0; 27 | 28 | /**图片加载的占位图片*/ 29 | public static int placeResId=R.mipmap.image_chooser_placeholder; 30 | 31 | /**图片加载的动画*/ 32 | public static int loadAnimateResId=0; 33 | 34 | /**拍照设置*/ 35 | public static int takePhotoType=TP_SYSTEM; 36 | 37 | public static int tackPhotoIcon=0; 38 | 39 | /**选中图片的滤镜颜色*/ 40 | public static int chooseFilter=0x55000000; 41 | 42 | /**未被选中的图片的滤镜颜色*/ 43 | public static int unChooseFilter=0; 44 | 45 | /**最新的图片集合显示名字*/ 46 | public static String newestAlbumName="最新图片"; 47 | 48 | /**最新图片集合的最大数量*/ 49 | public static int newestAlbumSize=100; 50 | 51 | public static int albumPopupHeight=600; 52 | 53 | public static String tantoToast=""; 54 | 55 | /**照片选择指示器*/ 56 | public static IChooseDrawable chooseDrawable=new CircleChooseDrawable(true,0xFF25c2e6); 57 | 58 | /**临时文件存储位置*/ 59 | public static String tempFolder= Environment.getExternalStorageDirectory().getAbsolutePath()+"/Wuwang/"; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/EntryActivity.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser; 2 | 3 | import android.app.Activity; 4 | import android.content.BroadcastReceiver; 5 | import android.content.ContentResolver; 6 | import android.content.ContentValues; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.IntentFilter; 10 | import android.content.res.Resources; 11 | import android.database.ContentObserver; 12 | import android.graphics.Bitmap; 13 | import android.graphics.Rect; 14 | import android.media.MediaScannerConnection; 15 | import android.net.Uri; 16 | import android.os.Bundle; 17 | import android.provider.MediaStore; 18 | import android.support.annotation.Nullable; 19 | import android.support.v4.app.FragmentActivity; 20 | import android.support.v7.widget.Toolbar; 21 | import android.view.MenuItem; 22 | import android.view.View; 23 | import android.widget.Toast; 24 | 25 | import com.wuwang.imagechooser.abslayer.IPhotoShoot; 26 | import com.wuwang.imagechooser.album.AlbumEntry; 27 | import com.wuwang.imagechooser.album.AlbumPopup; 28 | import com.wuwang.imagechooser.album.FolderFragment; 29 | import com.wuwang.imagechooser.album.ImageFolder; 30 | import com.wuwang.imagechooser.album.ImageInfo; 31 | import com.wuwang.utils.LogUtils; 32 | 33 | import java.io.File; 34 | import java.util.ArrayList; 35 | import java.util.List; 36 | 37 | /** 38 | * Description: 39 | */ 40 | public class EntryActivity extends FragmentActivity implements IPhotoShoot{ 41 | 42 | private AlbumEntry entry; 43 | private Toolbar toolbar; 44 | private MenuItem mSure; 45 | 46 | private String tackPicStr; 47 | private static final int REQ_TACK_PIC=0x15; 48 | 49 | @Override 50 | protected void onCreate(@Nullable Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | setContentView(R.layout.image_chooser_activity_entry); 53 | setTitle(); 54 | Rect outRect=new Rect(); 55 | getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect); 56 | ChooserSetting.albumPopupHeight=(int) (outRect.height()*0.6f); 57 | // mAlbumNum= (TextView) findViewById(R.id.mAlbum); 58 | // mAlbumNum.setOnClickListener(new View.OnClickListener() { 59 | // @Override 60 | // public void onClick(View v) { 61 | // entry.showAlbumChooser(); 62 | // } 63 | // }); 64 | // findViewById(R.id.mSure).setOnClickListener(new View.OnClickListener() { 65 | // @Override 66 | // public void onClick(View v) { 67 | // entry.chooseFinish(); 68 | // } 69 | // }); 70 | FolderFragment m=new FolderFragment(); 71 | m.setPhotoShoot(this); 72 | m.setSelectImgs(getIntent().getStringArrayListExtra(IcFinal.INTENT_EXIST_DATA)); 73 | entry=new AlbumEntry(this, R.id.mEntry, m, new AlbumPopup(this,toolbar,m)){ 74 | @Override 75 | public void onAlbumClick(ImageFolder folder) { 76 | super.onAlbumClick(folder); 77 | // toolbar.setTitle(folder.getName()+"("+folder.getCount()+")"); 78 | } 79 | 80 | @Override 81 | public boolean onAdd(List data, ImageInfo info) { 82 | boolean a=super.onAdd(data, info); 83 | if(!a&&mSure!=null&&getMax()!=1){ 84 | mSure.setEnabled(true); 85 | } 86 | return a; 87 | } 88 | 89 | @Override 90 | public boolean onCancel(List data, ImageInfo info) { 91 | boolean a=super.onCancel(data, info); 92 | if(!a&&mSure!=null&&data.size()<=1){ 93 | mSure.setEnabled(false); 94 | } 95 | return a; 96 | } 97 | }; 98 | 99 | if(entry.getMax()>1){ 100 | mSure=toolbar.getMenu().getItem(1); 101 | mSure.setEnabled(false); 102 | }else{ 103 | toolbar.getMenu().getItem(1).setVisible(false); 104 | } 105 | 106 | // IntentFilter filter=new IntentFilter(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); 107 | // registerReceiver(receiver,filter); 108 | } 109 | 110 | BroadcastReceiver receiver=new BroadcastReceiver() { 111 | @Override 112 | public void onReceive(Context context, Intent intent) { 113 | entry.refreshData(); 114 | } 115 | }; 116 | 117 | private void setTitle(){ 118 | toolbar= (Toolbar) findViewById(R.id.mTitle); 119 | toolbar.setBackgroundColor(ChooserSetting.TITLE_COLOR); 120 | toolbar.setTitle("图片选择"); 121 | toolbar.setNavigationIcon(R.mipmap.image_chooser_back); 122 | toolbar.setContentInsetStartWithNavigation(0); 123 | toolbar.inflateMenu(R.menu.menu_album); 124 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 125 | @Override 126 | public void onClick(View v) { 127 | finish(); 128 | } 129 | }); 130 | toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { 131 | @Override 132 | public boolean onMenuItemClick(MenuItem item) { 133 | int i = item.getItemId(); 134 | if (i == R.id.mAlbum) { 135 | entry.showAlbumChooser(); 136 | }else if(i==R.id.mSure){ 137 | entry.chooseFinish(); 138 | } 139 | return false; 140 | } 141 | }); 142 | } 143 | 144 | @Override 145 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 146 | super.onActivityResult(requestCode, resultCode, data); 147 | LogUtils.e("result-"+resultCode+"/"+requestCode); 148 | entry.onActivityResult(requestCode, resultCode, data); 149 | if(resultCode== Activity.RESULT_OK){ 150 | if(requestCode==REQ_TACK_PIC){ 151 | //Bitmap bmp= (Bitmap) data.getExtras().get("data"); 152 | //让拍摄的图片可以在相册目录中出现 153 | 154 | sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(tackPicStr)))); 155 | 156 | if(entry.isCrop()){ 157 | entry.crop(tackPicStr); 158 | }else{ 159 | Intent intent=new Intent(); 160 | ArrayList d=new ArrayList<>(); 161 | d.add(tackPicStr); 162 | intent.putExtra(IcFinal.RESULT_DATA_IMG,d); 163 | setResult(Activity.RESULT_OK,intent); 164 | finish(); 165 | } 166 | } 167 | } 168 | } 169 | 170 | @Override 171 | protected void onDestroy() { 172 | super.onDestroy(); 173 | // unregisterReceiver(receiver); 174 | } 175 | 176 | @Override 177 | public void takePhoto() { 178 | Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 179 | //TODO 传入保存路径直接保存 180 | tackPicStr=ChooserSetting.tempFolder+"photo/"+System.currentTimeMillis()+".jpg"; 181 | File folder=new File(ChooserSetting.tempFolder+"photo/"); 182 | if(!folder.exists()){ 183 | if(!folder.mkdirs()){ 184 | Toast.makeText(this,"无法拍照",Toast.LENGTH_SHORT).show(); 185 | return; 186 | } 187 | } 188 | File file = new File(tackPicStr); 189 | Uri imageUri = Uri.fromFile(file); 190 | intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); 191 | startActivityForResult(intent,REQ_TACK_PIC); 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/IcFinal.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser; 2 | 3 | /** 4 | * Description: 5 | */ 6 | public class IcFinal { 7 | public static final int NOW_COUNT=0; 8 | 9 | public static final String INTENT_MAX_IMG="ic_final_max_pic"; 10 | public static final String INTENT_IS_CROP="ic_final_is_crop"; 11 | public static final String INTENT_CROP_WIDTH="ic_final_crop_width"; 12 | public static final String INTENT_CROP_HEIGHT="ic_final_crop_height"; 13 | public static final String INTENT_CROP_SHAPE="ic_final_crop_shape"; 14 | public static final String INTENT_CROP_DATA="ic_final_crop_data"; 15 | public static final String INTENT_CROP_COVER="ic_final_crop_set"; 16 | public static final String INTENT_CROP_PARAM="ic_final_crop_param"; 17 | public static final String INTENT_EXIST_DATA="ic_final_exist_data"; 18 | 19 | public static final String RESULT_DATA_IMG="ic_final_img"; 20 | 21 | public static final String ACTION_ALBUM="android.intent.action.wuwang.album"; 22 | public static final String ACTION_CROP="android.intent.action.wuwang.crop"; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/abslayer/IAlpha.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.abslayer; 2 | 3 | /** 4 | * Description: 5 | */ 6 | public interface IAlpha { 7 | 8 | void setAlpha(int alpha); 9 | void show(); 10 | void hide(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/abslayer/IImageClickListener.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.abslayer; 2 | 3 | import com.wuwang.imagechooser.album.ImageInfo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Description: 9 | */ 10 | public interface IImageClickListener { 11 | 12 | //返回值为是否阻止默认操作,默认会增加选中 13 | boolean onAdd(List data,ImageInfo info); 14 | //返回值为是否阻止默认操作,默认会取消选中 15 | boolean onCancel(List data,ImageInfo info); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/abslayer/IPhotoShoot.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.abslayer; 2 | 3 | /** 4 | * Created by wuwang on 2016/11/10 5 | */ 6 | 7 | public interface IPhotoShoot { 8 | 9 | void takePhoto(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/AbsAlbumEntry.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | /** 4 | * Description: 5 | */ 6 | public abstract class AbsAlbumEntry { 7 | 8 | private int max=9; 9 | private int min=1; 10 | private boolean isCrop; 11 | 12 | public void setMax(int max){ 13 | this.max=max; 14 | } 15 | 16 | public void setMin(int min){ 17 | this.min=min; 18 | } 19 | 20 | public void setCrop(boolean isCrop){ 21 | this.isCrop=isCrop; 22 | } 23 | 24 | public int getMax(){ 25 | return this.max; 26 | } 27 | 28 | public int getMin(){ 29 | return this.min; 30 | } 31 | 32 | public boolean isCrop(){ 33 | return this.isCrop; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/AlbumAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.bumptech.glide.DrawableRequestBuilder; 12 | import com.bumptech.glide.Glide; 13 | import com.wuwang.imagechooser.ChooserSetting; 14 | import com.wuwang.imagechooser.R; 15 | 16 | import java.util.ArrayList; 17 | import java.util.Locale; 18 | 19 | /** 20 | * Description: 21 | */ 22 | public class AlbumAdapter extends BaseAdapter { 23 | 24 | private ArrayList data; 25 | private Context context; 26 | 27 | public AlbumAdapter(Context context, ArrayList data){ 28 | this.context=context; 29 | this.data=data; 30 | } 31 | 32 | @Override 33 | public int getCount() { 34 | return data==null?0:data.size(); 35 | } 36 | 37 | @Override 38 | public Object getItem(int position) { 39 | return data.get(position); 40 | } 41 | 42 | @Override 43 | public long getItemId(int position) { 44 | return position; 45 | } 46 | 47 | @Override 48 | public View getView(int position, View convertView, ViewGroup parent) { 49 | FolderHolder holder; 50 | if(convertView==null){ 51 | convertView= LayoutInflater.from(context).inflate(R.layout.image_chooser_item_album,parent,false); 52 | holder=new FolderHolder(convertView); 53 | }else{ 54 | holder= (FolderHolder) convertView.getTag(); 55 | } 56 | holder.setData(data.get(position)); 57 | return convertView; 58 | } 59 | 60 | private class FolderHolder{ 61 | ImageView mImage; 62 | TextView mInfo; 63 | FolderHolder(View view){ 64 | mImage= (ImageView) view.findViewById(R.id.mImage); 65 | mInfo= (TextView) view.findViewById(R.id.mInfo); 66 | view.setTag(this); 67 | } 68 | 69 | void setData(ImageFolder folder){ 70 | //图片加载 71 | DrawableRequestBuilder r= Glide.with(context).load(folder.getFirstImagePath()) 72 | .error(ChooserSetting.errorResId) 73 | .placeholder(ChooserSetting.placeResId); 74 | if(ChooserSetting.loadAnimateResId<=0){ 75 | r.dontAnimate(); 76 | }else{ 77 | r.animate(ChooserSetting.loadAnimateResId); 78 | } 79 | r.into(mImage); 80 | mInfo.setText(String.format(Locale.CHINA,"%1$s(%2$d)",folder.getName(),folder.getCount())); 81 | } 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/AlbumEntry.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentActivity; 7 | import android.widget.Toast; 8 | 9 | import com.wuwang.imagechooser.ChooserSetting; 10 | import com.wuwang.imagechooser.IcFinal; 11 | import com.wuwang.imagechooser.abslayer.IImageClickListener; 12 | import com.wuwang.imagechooser.res.IChooseDrawable; 13 | import com.wuwang.utils.LogUtils; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | * Description: 20 | */ 21 | public class AlbumEntry extends AbsAlbumEntry implements AlbumTool.Callback,IAlbumClickListener,IImageClickListener { 22 | 23 | private FragmentActivity activity; 24 | private int containerId; 25 | private IFolderShower folderShower; 26 | private IAlbumShower albumShower; 27 | 28 | private Intent actIntent; 29 | 30 | private AlbumTool tool; 31 | 32 | private final int REQ_CROP=0x10; 33 | 34 | public AlbumEntry(FragmentActivity activity, int containerId, IFolderShower fShower, IAlbumShower aShower){ 35 | this.activity=activity; 36 | this.containerId=containerId; 37 | this.folderShower=fShower; 38 | this.albumShower=aShower; 39 | init(); 40 | } 41 | 42 | private void init(){ 43 | activity.getSupportFragmentManager() 44 | .beginTransaction() 45 | .add(containerId,folderShower.getFragment()) 46 | .commitAllowingStateLoss(); 47 | albumShower.setAlbumClickListener(this); 48 | folderShower.setImageClickListener(this); 49 | tool=new AlbumTool(activity); 50 | tool.setCallback(this); 51 | tool.findAlbumsAsync(); 52 | 53 | actIntent=activity.getIntent(); 54 | setCrop(actIntent.getBooleanExtra(IcFinal.INTENT_IS_CROP,false)); 55 | if(isCrop()){ 56 | setMax(1); 57 | }else{ 58 | setMax(actIntent.getIntExtra(IcFinal.INTENT_MAX_IMG,getMax())); 59 | } 60 | if(getMax()==1){ 61 | this.folderShower.setChooseDrawable(null); 62 | }else{ 63 | this.folderShower.setChooseDrawable(ChooserSetting.chooseDrawable); 64 | } 65 | } 66 | 67 | public void refreshData(){ 68 | tool.findAlbumsAsync(); 69 | } 70 | 71 | //显示相册选择器 72 | public void showAlbumChooser(){ 73 | LogUtils.e("显示相册选择器"); 74 | albumShower.show(); 75 | } 76 | 77 | //关闭相册选择器 78 | public void cancelAlbumChooser(){ 79 | albumShower.cancel(); 80 | } 81 | 82 | @Override 83 | public void onFolderFinish(ImageFolder folder) { 84 | LogUtils.e("图片集《"+folder.getName()+"》查找完毕"); 85 | folderShower.setFolder(folder); 86 | } 87 | 88 | @Override 89 | public void onAlbumFinish(ArrayList albums) { 90 | LogUtils.e("相册查找完毕,共"+albums.size()+"个相册"); 91 | albumShower.setAlbums(albums); 92 | } 93 | 94 | @Override 95 | public void onAlbumClick(ImageFolder folder) { 96 | tool.findFolderAsync(folder); 97 | cancelAlbumChooser(); 98 | } 99 | 100 | public void crop(String path){ 101 | int shape=actIntent.getIntExtra(IcFinal.INTENT_CROP_SHAPE,0); 102 | Intent intent=new Intent(IcFinal.ACTION_CROP); 103 | intent.putExtra(IcFinal.INTENT_CROP_DATA,path); 104 | intent.putExtra(IcFinal.INTENT_CROP_SHAPE,shape); 105 | if(shape==0){ 106 | intent.putExtra(IcFinal.INTENT_CROP_COVER,actIntent.getStringExtra(IcFinal.INTENT_CROP_COVER)); 107 | intent.putExtra(IcFinal.INTENT_CROP_PARAM,actIntent.getIntExtra(IcFinal.INTENT_CROP_PARAM,0)); 108 | }else{ 109 | intent.putExtra(IcFinal.INTENT_CROP_WIDTH,actIntent.getIntExtra(IcFinal.INTENT_CROP_WIDTH,500)); 110 | intent.putExtra(IcFinal.INTENT_CROP_HEIGHT,actIntent.getIntExtra(IcFinal.INTENT_CROP_HEIGHT,500)); 111 | } 112 | activity.startActivityForResult(intent,REQ_CROP); 113 | } 114 | 115 | @Override 116 | public boolean onAdd(List data, ImageInfo info) { 117 | if(getMax()==1){ 118 | if(isCrop()){ 119 | crop(info.path); 120 | }else{ 121 | Intent intent=new Intent(); 122 | ArrayList result=new ArrayList<>(); 123 | result.add(info.path); 124 | intent.putExtra(IcFinal.RESULT_DATA_IMG,result); 125 | activity.setResult(Activity.RESULT_OK,intent); 126 | activity.finish(); 127 | } 128 | return true; 129 | }else{ 130 | if(data.size()==getMax()){ 131 | Toast.makeText(activity,"无法继续选中",Toast.LENGTH_SHORT).show(); 132 | return true; 133 | } 134 | } 135 | return false; 136 | } 137 | 138 | public void chooseFinish(){ 139 | List res=folderShower.getSelectedImages(); 140 | int resSize=res.size(); 141 | if(resSize>0){ 142 | ArrayList data=new ArrayList<>(resSize); 143 | for (int i=0;i data){ 159 | if(data.size()>0){ 160 | Intent intent=new Intent(); 161 | intent.putExtra(IcFinal.RESULT_DATA_IMG,data); 162 | activity.setResult(Activity.RESULT_OK,intent); 163 | activity.finish(); 164 | } 165 | } 166 | 167 | private void chooseFinish(String data){ 168 | if(data!=null){ 169 | ArrayList c=new ArrayList<>(1); 170 | c.add(data); 171 | chooseFinish(c); 172 | } 173 | } 174 | 175 | @Override 176 | public boolean onCancel(List data, ImageInfo info) { 177 | return false; 178 | } 179 | 180 | public interface IAlbumShower{ 181 | void setAlbums(ArrayList albums); 182 | void setAlbumClickListener(IAlbumClickListener listener); 183 | void show(); 184 | void cancel(); 185 | } 186 | 187 | public interface IFolderShower{ 188 | void setChooseDrawable(IChooseDrawable drawable); 189 | void setFolder(ImageFolder folder); 190 | void setImageClickListener(IImageClickListener listener); 191 | List getSelectedImages(); 192 | Fragment getFragment(); 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/AlbumPopup.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | import android.app.Activity; 4 | import android.graphics.drawable.ColorDrawable; 5 | import android.view.LayoutInflater; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.AdapterView; 10 | import android.widget.ListView; 11 | import android.widget.PopupWindow; 12 | 13 | import com.wuwang.imagechooser.ChooserSetting; 14 | import com.wuwang.imagechooser.R; 15 | import com.wuwang.imagechooser.abslayer.IAlpha; 16 | 17 | import java.util.ArrayList; 18 | 19 | /** 20 | * Description: 21 | */ 22 | public class AlbumPopup implements AlbumEntry.IAlbumShower{ 23 | 24 | private Activity context; 25 | private PopupWindow window; 26 | private View contentView; 27 | private ListView mList; 28 | private AlbumAdapter adapter; 29 | private ArrayList data; 30 | private IAlbumClickListener listener; 31 | private IAlpha alpha; 32 | private View anchor; 33 | 34 | public AlbumPopup(Activity context, View anchor, IAlpha iAlpha){ 35 | this.context=context; 36 | this.anchor=anchor; 37 | this.alpha=iAlpha; 38 | createPopup(); 39 | } 40 | 41 | private void createPopup(){ 42 | contentView= LayoutInflater.from(context).inflate(R.layout.image_chooser_fragment_folder,null); 43 | window=new PopupWindow(contentView, ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT); 44 | window.setBackgroundDrawable(new ColorDrawable(0)); 45 | window.setTouchable(true); 46 | window.setOutsideTouchable(true); 47 | window.setFocusable(true); 48 | window.setOnDismissListener(new PopupWindow.OnDismissListener() { 49 | @Override 50 | public void onDismiss() { 51 | alpha.hide(); 52 | } 53 | }); 54 | window.setTouchInterceptor(new View.OnTouchListener() { 55 | @Override 56 | public boolean onTouch(View v, MotionEvent event) { 57 | if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { 58 | window.dismiss(); 59 | return true; 60 | } 61 | return false; 62 | } 63 | }); 64 | mList= (ListView) contentView.findViewById(R.id.mList); 65 | adapter=new AlbumAdapter(context,data=new ArrayList<>()); 66 | mList.setAdapter(adapter); 67 | mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { 68 | @Override 69 | public void onItemClick(AdapterView parent, View view, int position, long id) { 70 | listener.onAlbumClick(data.get(position)); 71 | } 72 | }); 73 | contentView.setOnClickListener(new View.OnClickListener() { 74 | @Override 75 | public void onClick(View v) { 76 | window.dismiss(); 77 | } 78 | }); 79 | } 80 | 81 | @Override 82 | public void setAlbums(ArrayList albums) { 83 | data.clear(); 84 | data.addAll(albums); 85 | adapter.notifyDataSetChanged(); 86 | mList.pointToPosition(0,0); 87 | } 88 | 89 | @Override 90 | public void setAlbumClickListener(IAlbumClickListener listener) { 91 | this.listener=listener; 92 | } 93 | 94 | @Override 95 | public void show() { 96 | alpha.show(); 97 | mList.getLayoutParams().height= ChooserSetting.albumPopupHeight; 98 | mList.setLayoutParams(mList.getLayoutParams()); 99 | window.showAsDropDown(anchor); 100 | } 101 | 102 | @Override 103 | public void cancel() { 104 | window.dismiss(); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/AlbumTool.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.graphics.ImageFormat; 7 | import android.os.Handler; 8 | import android.os.Looper; 9 | import android.os.Message; 10 | import android.provider.MediaStore; 11 | 12 | import com.wuwang.imagechooser.ChooserSetting; 13 | 14 | import java.io.File; 15 | import java.io.FilenameFilter; 16 | import java.util.ArrayList; 17 | import java.util.concurrent.Semaphore; 18 | 19 | /** 20 | * Description: 21 | */ 22 | public class AlbumTool { 23 | 24 | private Handler handler; 25 | //private Semaphore semaphore; 26 | private Callback callback; 27 | private Context context; 28 | 29 | private final int TYPE_FOLDER=1; 30 | private final int TYPE_ALBUM=2; 31 | 32 | public AlbumTool(Context context){ 33 | this.context=context; 34 | handler=new Handler(Looper.getMainLooper()){ 35 | @Override 36 | public void handleMessage(Message msg) { 37 | if(callback!=null){ 38 | switch (msg.what){ 39 | case TYPE_FOLDER: 40 | callback.onFolderFinish((ImageFolder) msg.obj); 41 | break; 42 | case TYPE_ALBUM: 43 | callback.onAlbumFinish((ArrayList) msg.obj); 44 | break; 45 | } 46 | } 47 | super.handleMessage(msg); 48 | } 49 | }; 50 | } 51 | 52 | public void setCallback(Callback callback){ 53 | this.callback=callback; 54 | } 55 | 56 | public void findAlbumsAsync(){ 57 | new Thread(new Runnable() { 58 | @Override 59 | public void run() { 60 | getAlbums(context); 61 | } 62 | }).start(); 63 | } 64 | 65 | public void findFolderAsync(final ImageFolder folder){ 66 | new Thread(new Runnable() { 67 | @Override 68 | public void run() { 69 | getFolder(context,folder); 70 | } 71 | }).start(); 72 | } 73 | 74 | //获取所有图片集 75 | private ArrayList getAlbums(Context context) { 76 | ArrayList albums=new ArrayList<>(); 77 | albums.add(getNewestPhotos(context)); 78 | //利用ContentResolver查询数据库,找出所有包含图片的文件夹,保存到相册列表中 79 | ContentResolver resolver = context.getContentResolver(); 80 | Cursor cursor = resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 81 | new String[]{ 82 | MediaStore.Images.Media.DATA, 83 | MediaStore.Images.ImageColumns.BUCKET_ID, 84 | MediaStore.Images.Media.DATE_MODIFIED, 85 | "count(*) as count" 86 | }, 87 | MediaStore.Images.Media.MIME_TYPE + "=? or " + 88 | MediaStore.Images.Media.MIME_TYPE + "=? or " + 89 | MediaStore.Images.Media.MIME_TYPE + "=?) " + 90 | "group by (" + MediaStore.Images.ImageColumns.BUCKET_ID, 91 | new String[]{"image/jpeg", "image/png", "image/jpg"}, 92 | MediaStore.Images.Media.DATE_MODIFIED + " desc"); 93 | if (cursor != null) { 94 | while (cursor.moveToNext()) { 95 | final File file = new File(cursor.getString(0)); 96 | ImageFolder imageFolder = new ImageFolder(); 97 | imageFolder.setDir(file.getParent()); 98 | imageFolder.setId(cursor.getString(1)); 99 | imageFolder.setFirstImagePath(cursor.getString(0)); 100 | String[] all=file.getParentFile().list(new FilenameFilter() { 101 | 102 | private boolean e(String filename,String ends){ 103 | return filename.toLowerCase().endsWith(ends); 104 | } 105 | 106 | @Override 107 | public boolean accept(File dir, String filename) { 108 | return e(filename,".png") || e(filename,".jpg") || e(filename,"jpeg"); 109 | } 110 | }); 111 | if(all!=null&&all.length>0){ 112 | imageFolder.setCount(all.length); 113 | albums.add(imageFolder); 114 | } 115 | } 116 | cursor.close(); 117 | } 118 | sendMessage(TYPE_ALBUM,albums); 119 | return albums; 120 | } 121 | 122 | //获取《最新图片》集 123 | private ImageFolder getNewestPhotos(Context context) { 124 | ImageFolder newestFolder=new ImageFolder(); 125 | newestFolder.setName(ChooserSetting.newestAlbumName); 126 | ArrayList imageBeans = new ArrayList<>(); 127 | ContentResolver resolver = context.getContentResolver(); 128 | Cursor cursor = resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 129 | new String[]{ 130 | MediaStore.Images.Media.DATA, 131 | MediaStore.Images.Media.DISPLAY_NAME, 132 | MediaStore.Images.Media.DATE_MODIFIED, 133 | }, 134 | MediaStore.Images.Media.MIME_TYPE + "=? or " 135 | + MediaStore.Images.Media.MIME_TYPE + "=? or " 136 | + MediaStore.Images.Media.MIME_TYPE + "=?", 137 | new String[]{"image/jpeg", "image/png", "image/jpg"}, 138 | MediaStore.Images.Media.DATE_MODIFIED + " desc" 139 | + (ChooserSetting.newestAlbumSize < 0 ? "" 140 | : (" limit " + ChooserSetting.newestAlbumSize))); 141 | if (cursor != null){ 142 | while (cursor.moveToNext()) { 143 | ImageInfo info=new ImageInfo(); 144 | info.path=cursor.getString(0); 145 | info.displayName=cursor.getString(1); 146 | info.time=cursor.getLong(2); 147 | imageBeans.add(info); 148 | } 149 | cursor.close(); 150 | newestFolder.setFirstImagePath(imageBeans.get(0).path); 151 | newestFolder.setDatas(imageBeans); 152 | newestFolder.setCount(imageBeans.size()); 153 | } 154 | sendMessage(TYPE_FOLDER,newestFolder); 155 | return newestFolder; 156 | } 157 | 158 | //获取具体图片集,确保图片数据已被查询 159 | private ImageFolder getFolder(Context context,ImageFolder folder) { 160 | ContentResolver resolver = context.getContentResolver(); 161 | Cursor cursor; 162 | if(folder!=null&&folder.getDatas()!=null&&folder.getDatas().size()>0){ 163 | sendMessage(TYPE_FOLDER,folder); 164 | return folder; 165 | } 166 | if (folder == null) { 167 | return getNewestPhotos(context); 168 | } else { 169 | cursor = resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 170 | new String[]{ 171 | MediaStore.Images.Media.DATA, 172 | MediaStore.Images.Media.DISPLAY_NAME, 173 | MediaStore.Images.Media.DATE_MODIFIED 174 | }, 175 | MediaStore.Images.ImageColumns.BUCKET_ID + "=? and (" + 176 | MediaStore.Images.Media.MIME_TYPE + "=? or " 177 | + MediaStore.Images.Media.MIME_TYPE + "=? or " 178 | + MediaStore.Images.Media.MIME_TYPE + "=?) ", 179 | new String[]{folder.getId(), "image/jpeg", "image/png", "image/jpg"}, 180 | MediaStore.Images.Media.DATE_MODIFIED + " desc"); 181 | } 182 | ArrayList datas=new ArrayList<>(); 183 | folder.setDatas(datas); 184 | if (cursor != null){ 185 | while (cursor.moveToNext()) { 186 | ImageInfo info=new ImageInfo(); 187 | info.path=cursor.getString(0); 188 | info.displayName=cursor.getString(1); 189 | info.time=cursor.getLong(2); 190 | datas.add(info); 191 | } 192 | cursor.close(); 193 | } 194 | folder.setCount(datas.size()); 195 | sendMessage(TYPE_FOLDER,folder); 196 | return folder; 197 | } 198 | 199 | private void sendMessage(int what,Object obj){ 200 | Message msg=new Message(); 201 | msg.what=what; 202 | msg.obj=obj; 203 | handler.sendMessage(msg); 204 | } 205 | 206 | public interface Callback{ 207 | 208 | //文件夹查找完毕 209 | void onFolderFinish(ImageFolder folder); 210 | //成功搜索出所有的图片集 211 | void onAlbumFinish(ArrayList albums); 212 | 213 | } 214 | 215 | } 216 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/AlbumVar.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | /** 4 | * Description: 5 | */ 6 | public class AlbumVar { 7 | 8 | private static AlbumVar instance; 9 | private int goal; 10 | private int now; 11 | 12 | private AlbumVar(){ 13 | 14 | } 15 | 16 | public static AlbumVar getInstance(){ 17 | if(null==instance){ 18 | synchronized (AlbumVar.class){ 19 | if(null==instance){ 20 | instance=new AlbumVar(); 21 | } 22 | } 23 | } 24 | return instance; 25 | } 26 | 27 | public void init(int goal,int now){ 28 | this.goal=goal; 29 | this.now=now; 30 | } 31 | 32 | public void nowAdd(){ 33 | 34 | } 35 | 36 | public void nowDec(){ 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/FolderAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.support.v4.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.BaseAdapter; 9 | import android.widget.ImageView; 10 | 11 | import com.bumptech.glide.DrawableRequestBuilder; 12 | import com.bumptech.glide.Glide; 13 | import com.wuwang.imagechooser.ChooserSetting; 14 | import com.wuwang.imagechooser.R; 15 | import com.wuwang.imagechooser.res.IChooseDrawable; 16 | 17 | import java.util.ArrayList; 18 | 19 | /** 20 | * Description: 21 | */ 22 | public class FolderAdapter extends BaseAdapter { 23 | 24 | private IChooseDrawable drawable; 25 | private Fragment fragment; 26 | public ArrayList data; 27 | 28 | private final int TYPE_DEFAULT=0; 29 | private final int TYPE_TAKEPIC=1; 30 | 31 | private boolean isTackPhoto=ChooserSetting.takePhotoType!=ChooserSetting.TP_NONE; 32 | 33 | public FolderAdapter(Fragment fragment, ArrayList data, IChooseDrawable drawable){ 34 | this.fragment=fragment; 35 | this.data=data; 36 | this.drawable=drawable; 37 | } 38 | 39 | public void setChooseDrawable(IChooseDrawable drawable){ 40 | this.drawable=drawable; 41 | } 42 | 43 | @Override 44 | public int getCount() { 45 | return data==null?0:data.size(); 46 | } 47 | 48 | @Override 49 | public Object getItem(int position) { 50 | return data.get(position); 51 | } 52 | 53 | @Override 54 | public long getItemId(int position) { 55 | return position; 56 | } 57 | 58 | @Override 59 | public int getItemViewType(int position) { 60 | if(position==0&&isTackPhoto){ 61 | return TYPE_TAKEPIC; 62 | } 63 | return TYPE_DEFAULT; 64 | } 65 | 66 | public boolean isTakePhoto(int position){ 67 | return getItemViewType(position)==TYPE_TAKEPIC; 68 | } 69 | 70 | @Override 71 | public View getView(int position, View convertView, ViewGroup parent) { 72 | if(getItemViewType(position)==TYPE_TAKEPIC){ 73 | convertView= LayoutInflater.from(fragment.getContext()).inflate(R.layout.image_chooser_item_camera,parent,false); 74 | if(ChooserSetting.tackPhotoIcon>0){ 75 | ((ImageView)convertView).setImageResource(ChooserSetting.tackPhotoIcon); 76 | } 77 | }else{ 78 | ImageHolder holder; 79 | if(convertView==null||convertView.getTag()==null){ 80 | convertView= LayoutInflater.from(fragment.getContext()).inflate(R.layout.image_chooser_item_image,parent,false); 81 | holder=new ImageHolder(convertView); 82 | }else{ 83 | holder= (ImageHolder) convertView.getTag(); 84 | } 85 | holder.setData(data.get(position)); 86 | } 87 | return convertView; 88 | } 89 | 90 | private class ImageHolder{ 91 | ImageView mImage; 92 | View mFlag; 93 | ImageHolder(View convertView){ 94 | mImage= (ImageView) convertView.findViewById(R.id.mImage); 95 | mFlag=convertView.findViewById(R.id.mFlag); 96 | convertView.setTag(this); 97 | } 98 | 99 | void setData(ImageInfo info){ 100 | //图片加载 101 | DrawableRequestBuilder r=Glide.with(fragment).load(info.path) 102 | .error(ChooserSetting.errorResId) 103 | .placeholder(ChooserSetting.placeResId); 104 | if(ChooserSetting.loadAnimateResId<=0){ 105 | r.dontAnimate(); 106 | }else{ 107 | r.animate(ChooserSetting.loadAnimateResId); 108 | } 109 | r.into(mImage); 110 | 111 | //状态加载 112 | if(drawable!=null){ 113 | if(info.state<=0){ 114 | mImage.setColorFilter(ChooserSetting.unChooseFilter); 115 | }else{ 116 | mImage.setColorFilter(ChooserSetting.chooseFilter); 117 | } 118 | setBg(mFlag,drawable.get(info.state)); 119 | } 120 | } 121 | 122 | private void setBg(View v, Drawable drawable){ 123 | v.setBackgroundDrawable(null); 124 | v.setBackgroundDrawable(drawable); 125 | } 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/FolderFragment.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.os.Environment; 9 | import android.provider.MediaStore; 10 | import android.support.annotation.Nullable; 11 | import android.support.v4.app.Fragment; 12 | import android.support.v4.os.EnvironmentCompat; 13 | import android.util.Log; 14 | import android.view.LayoutInflater; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.AdapterView; 18 | import android.widget.GridView; 19 | 20 | import com.wuwang.imagechooser.ChooserSetting; 21 | import com.wuwang.imagechooser.IcFinal; 22 | import com.wuwang.imagechooser.R; 23 | import com.wuwang.imagechooser.abslayer.IAlpha; 24 | import com.wuwang.imagechooser.abslayer.IImageClickListener; 25 | import com.wuwang.imagechooser.abslayer.IPhotoShoot; 26 | import com.wuwang.imagechooser.res.IChooseDrawable; 27 | import com.wuwang.utils.LogUtils; 28 | 29 | import java.io.File; 30 | import java.util.ArrayList; 31 | import java.util.List; 32 | import java.util.Vector; 33 | 34 | /** 35 | * Description: 36 | */ 37 | public class FolderFragment extends Fragment implements AlbumEntry.IFolderShower,IAlpha { 38 | 39 | private ViewGroup rootView; 40 | private GridView mGrid; 41 | private View mCover; 42 | private FolderAdapter adapter; 43 | private ArrayList data=new ArrayList<>(); 44 | private Vector selectImgs; 45 | private IImageClickListener listener; 46 | private IChooseDrawable drawable; 47 | private IPhotoShoot photoShoot; 48 | 49 | private List initSelect; 50 | 51 | @Nullable 52 | @Override 53 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 54 | if(rootView==null){ 55 | rootView= (ViewGroup) LayoutInflater.from(getContext()).inflate(R.layout.image_chooser_fragment_album,container,false); 56 | initView(); 57 | initData(); 58 | } 59 | return rootView; 60 | } 61 | 62 | private void initView(){ 63 | mGrid= (GridView) rootView.findViewById(R.id.mAlbum); 64 | mGrid.setNumColumns(ChooserSetting.NUM_COLUMNS); 65 | mGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() { 66 | @Override 67 | public void onItemClick(AdapterView parent, View view, int position, long id) { 68 | if(adapter.isTakePhoto(position)){ 69 | if(photoShoot!=null){ 70 | photoShoot.takePhoto(); 71 | } 72 | }else{ 73 | ImageInfo info=data.get(position); 74 | if(info.state>0){ //点击已经选择过得 75 | boolean a=listener.onCancel(selectImgs,info); 76 | if(!a){ 77 | info.state=0; 78 | selectImgs.removeElement(info); 79 | int size=selectImgs.size(); 80 | for(int i=0;i data){ 103 | initSelect=data; 104 | } 105 | 106 | private void initData(){ 107 | adapter=new FolderAdapter(this,data,drawable); 108 | mGrid.setAdapter(adapter); 109 | selectImgs=new Vector<>(); 110 | if(initSelect!=null){ 111 | int size=initSelect.size(); 112 | for (int i=0;i getSelectedImages() { 169 | return selectImgs; 170 | } 171 | 172 | @Override 173 | public Fragment getFragment() { 174 | return this; 175 | } 176 | 177 | @Override 178 | public void setAlpha(int alpha) { 179 | mCover.setBackgroundColor(alpha); 180 | } 181 | 182 | @Override 183 | public void show() { 184 | mCover.setVisibility(View.VISIBLE); 185 | } 186 | 187 | @Override 188 | public void hide() { 189 | mCover.setVisibility(View.GONE); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/IAlbumClickListener.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | /** 4 | * Description: 5 | */ 6 | public interface IAlbumClickListener { 7 | 8 | void onAlbumClick(ImageFolder folder); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/ImageFolder.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Description: 7 | */ 8 | public class ImageFolder { 9 | 10 | private String dir; //文件路径 11 | private String firstImagePath; //第一张图片的路径 12 | private String name; //文件夹显示名称 13 | private int count; //图片的数量 14 | private String id; //文件夹在数据库中的id 15 | private ArrayList datas; //文件夹中图片 16 | 17 | public void setId(String id) { 18 | this.id = id; 19 | } 20 | 21 | public String getId() { 22 | return id; 23 | } 24 | 25 | public String getDir() { 26 | return dir; 27 | } 28 | 29 | public void setDir(String dir) { 30 | this.dir = dir; 31 | int lastIndexOf = this.dir.lastIndexOf("/"); 32 | this.name = this.dir.substring(lastIndexOf + 1); 33 | } 34 | 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | 39 | public String getFirstImagePath() { 40 | return firstImagePath; 41 | } 42 | 43 | public void setFirstImagePath(String firstImagePath) { 44 | this.firstImagePath = firstImagePath; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public int getCount() { 52 | return count; 53 | } 54 | 55 | public void setCount(int count) { 56 | this.count = count; 57 | } 58 | 59 | public void setDatas(ArrayList datas){ 60 | this.datas=datas; 61 | } 62 | 63 | public ArrayList getDatas(){ 64 | return datas; 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/album/ImageInfo.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.album; 2 | 3 | /** 4 | * Description: 5 | */ 6 | public class ImageInfo { 7 | 8 | public int state=0; 9 | public String path; 10 | public long time; 11 | public String displayName; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/crop/ACropCoverDrawable.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.crop; 2 | 3 | import android.graphics.drawable.Drawable; 4 | 5 | /** 6 | * Description: 7 | */ 8 | public abstract class ACropCoverDrawable extends Drawable implements CropPath{ 9 | 10 | public ACropCoverDrawable(int control){ 11 | 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/crop/CropActivity.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.crop; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.FragmentActivity; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | 12 | import com.wuwang.imagechooser.ChooserSetting; 13 | import com.wuwang.imagechooser.IcFinal; 14 | import com.wuwang.imagechooser.R; 15 | import com.wuwang.utils.LogUtils; 16 | 17 | import java.io.IOException; 18 | 19 | /** 20 | * Description: 21 | */ 22 | public class CropActivity extends FragmentActivity { 23 | 24 | private Toolbar toolbar; 25 | private CropFragment cropFragment; 26 | private int shape; 27 | private int width; 28 | private int height; 29 | private String drawableName; 30 | private int drawableParam; 31 | 32 | @Override 33 | protected void onCreate(@Nullable Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.image_chooser_activity_crop); 36 | setTitle(); 37 | initByIntent(); 38 | } 39 | 40 | public void initByIntent(){ 41 | Intent intent=getIntent(); 42 | String data=intent.getStringExtra(IcFinal.INTENT_CROP_DATA); 43 | shape=intent.getIntExtra(IcFinal.INTENT_CROP_SHAPE,0); 44 | if(shape==0){ 45 | drawableName= intent.getStringExtra(IcFinal.INTENT_CROP_COVER); 46 | drawableParam=intent.getIntExtra(IcFinal.INTENT_CROP_PARAM,0); 47 | cropFragment=CropFragment.newFragment(data,drawableName,drawableParam); 48 | }else if(shape==CropPath.SHAPE_CIRCLE||shape==CropPath.SHAPE_RECT){ 49 | width=intent.getIntExtra(IcFinal.INTENT_CROP_WIDTH,400); 50 | height=intent.getIntExtra(IcFinal.INTENT_CROP_HEIGHT,400); 51 | cropFragment=CropFragment.newFragment(data,shape,width,height); 52 | } 53 | cropFragment.setOnReadyRunnable(new Runnable() { 54 | @Override 55 | public void run() { 56 | toolbar.getMenu().getItem(0).setEnabled(true); 57 | } 58 | }); 59 | getSupportFragmentManager().beginTransaction() 60 | .add(R.id.mContainer,cropFragment) 61 | .commit(); 62 | } 63 | 64 | public void setTitle(){ 65 | toolbar= (Toolbar) findViewById(R.id.mTitle); 66 | toolbar.setBackgroundColor(ChooserSetting.TITLE_COLOR); 67 | toolbar.setTitle("裁剪图片"); 68 | toolbar.setNavigationIcon(R.mipmap.image_chooser_back); 69 | toolbar.setContentInsetStartWithNavigation(0); 70 | toolbar.inflateMenu(R.menu.menu_crop); 71 | toolbar.getMenu().getItem(0).setEnabled(false); 72 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 73 | @Override 74 | public void onClick(View v) { 75 | finish(); 76 | } 77 | }); 78 | toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { 79 | @Override 80 | public boolean onMenuItemClick(MenuItem item) { 81 | if(item.getItemId()==R.id.mSure){ 82 | String file=getFilesDir().getAbsolutePath()+"/temp.jpg"; 83 | try { 84 | cropFragment.crop(file); 85 | Intent intent=new Intent(); 86 | intent.putExtra(IcFinal.RESULT_DATA_IMG,file); 87 | setResult(RESULT_OK,intent); 88 | finish(); 89 | } catch (IOException e) { 90 | e.printStackTrace(); 91 | } 92 | } 93 | return false; 94 | } 95 | }); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/crop/CropCoverDrawable.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.crop; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.ColorFilter; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.graphics.PixelFormat; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuffXfermode; 11 | import android.graphics.Rect; 12 | import android.graphics.drawable.Drawable; 13 | import android.os.Build; 14 | import android.support.annotation.NonNull; 15 | 16 | /** 17 | * Created by wuwang on 2016/10/25 18 | */ 19 | 20 | public class CropCoverDrawable extends ACropCoverDrawable { 21 | 22 | private Paint paint; 23 | private Rect rect; 24 | private int width,height; 25 | private int shape; 26 | private Path cropPath; 27 | 28 | public CropCoverDrawable(int width,int height){ 29 | super(0); 30 | this.width=width; 31 | this.height=height; 32 | paintInit(); 33 | } 34 | 35 | public CropCoverDrawable(int shape,int x,int y,int width,int height){ 36 | super(0); 37 | this.shape=shape; 38 | rect=new Rect(x-width/2,y-height/2,x+width/2,y+height/2); 39 | paintInit(); 40 | } 41 | 42 | private void paintInit(){ 43 | paint=new Paint(); 44 | paint.setAntiAlias(true); 45 | paint.setColor(0x88000000); 46 | } 47 | 48 | public CropCoverDrawable setShape(int shape){ 49 | this.shape=shape; 50 | return this; 51 | } 52 | 53 | public void setShadowColor(int color){ 54 | paint.setColor(color); 55 | } 56 | 57 | @Override 58 | public void draw(@NonNull Canvas canvas) { 59 | int cWidth=canvas.getWidth(); 60 | int cHeight=canvas.getHeight(); 61 | if(rect==null){ 62 | rect=new Rect(cWidth/2-width/2,cHeight/2-height/2,cWidth/2+width/2,cHeight/2+height/2); 63 | } 64 | canvas.drawColor(Color.TRANSPARENT); 65 | Path path=new Path(); 66 | path.addRect(0,0,cWidth,cHeight, Path.Direction.CW); 67 | cropPath=new Path(); 68 | if(shape==SHAPE_RECT){ 69 | cropPath.addRect(rect.left,rect.top,rect.right,rect.bottom, Path.Direction.CW); 70 | }else if(shape==SHAPE_CIRCLE){ 71 | cropPath.addCircle(rect.centerX(),rect.centerY(),rect.width()/2, Path.Direction.CW); 72 | } 73 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 74 | path.op(cropPath, Path.Op.DIFFERENCE); //可以抗锯齿 75 | canvas.drawPath(path,paint); 76 | }else{ 77 | //此方法可以去掉锯齿 78 | //在这里saveLayer然后restoreToCount的操作不能少,否则不会得到想要的效果 79 | int layerId = canvas.saveLayer(0, 0, cWidth, cHeight, null, Canvas.ALL_SAVE_FLAG); 80 | canvas.drawPath(path,paint); 81 | //已经绘制的可以看做为目标图 82 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 83 | canvas.drawPath(cropPath,paint); 84 | paint.setXfermode(null); 85 | canvas.restoreToCount(layerId); 86 | //裁剪的方式会有锯齿,没找到方法去掉锯齿 87 | //canvas.clipPath(opPath, Region.Op.DIFFERENCE); 88 | //canvas.drawRect(0,0,cWidth,cHeight,paint); 89 | } 90 | } 91 | 92 | @Override 93 | public void setAlpha(int alpha) { 94 | paint.setAlpha(alpha); 95 | } 96 | 97 | @Override 98 | public void setColorFilter(ColorFilter colorFilter) { 99 | paint.setColorFilter(colorFilter); 100 | } 101 | 102 | @Override 103 | public int getOpacity() { 104 | return PixelFormat.TRANSPARENT; 105 | } 106 | 107 | @Override 108 | public Rect limit() { 109 | return rect; 110 | } 111 | 112 | @Override 113 | public Path path() { 114 | return cropPath; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/crop/CropFragment.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.crop; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | 12 | import com.bumptech.glide.Glide; 13 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 14 | import com.bumptech.glide.load.resource.drawable.GlideDrawable; 15 | import com.bumptech.glide.request.RequestListener; 16 | import com.bumptech.glide.request.animation.GlideAnimation; 17 | import com.bumptech.glide.request.target.GlideDrawableImageViewTarget; 18 | import com.bumptech.glide.request.target.Target; 19 | import com.wuwang.imagechooser.R; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.lang.reflect.Constructor; 24 | 25 | /** 26 | * Created by wuwang on 2016/11/4 27 | */ 28 | 29 | public class CropFragment extends Fragment { 30 | 31 | private View rootView; 32 | private ImageView mImage; 33 | private View mCover; 34 | 35 | private ACropCoverDrawable bg; 36 | private CropHelper helper; 37 | private Runnable ready; 38 | 39 | public static CropFragment newFragment(String path,int shape,int width,int height){ 40 | CropFragment f=new CropFragment(); 41 | Bundle b=new Bundle(); 42 | b.putString("path",path); 43 | b.putInt("shape",shape); 44 | b.putInt("width",width); 45 | b.putInt("height",height); 46 | f.setArguments(b); 47 | return f; 48 | } 49 | 50 | public static CropFragment newFragment(String path,String dName,int dParam){ 51 | CropFragment f=new CropFragment(); 52 | Bundle b=new Bundle(); 53 | b.putString("path",path); 54 | // b.putSerializable("cover",cover); 55 | b.putString("name",dName); 56 | b.putInt("param",dParam); 57 | f.setArguments(b); 58 | return f; 59 | } 60 | 61 | @Nullable 62 | @Override 63 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 64 | if(rootView==null){ 65 | rootView=inflater.inflate(R.layout.image_chooser_fragment_crop,container,false); 66 | mImage= (ImageView) rootView.findViewById(R.id.mImage); 67 | mCover=rootView.findViewById(R.id.mCover); 68 | initData(); 69 | } 70 | return rootView; 71 | } 72 | 73 | private void initData(){ 74 | Bundle b=getArguments(); 75 | String src=b.getString("path"); 76 | if(src!=null){ 77 | Glide.with(this).load(src).skipMemoryCache(true) 78 | .diskCacheStrategy(DiskCacheStrategy.NONE) 79 | .dontTransform() 80 | .dontAnimate() 81 | .into(new GlideDrawableImageViewTarget(mImage){ 82 | @Override 83 | public void onResourceReady(GlideDrawable resource, GlideAnimation animation) { 84 | super.onResourceReady(resource, animation); 85 | if(ready!=null){ 86 | ready.run(); 87 | } 88 | } 89 | }); 90 | } 91 | if(b.getInt("shape",-1)!=-1){ 92 | bg=new CropCoverDrawable(b.getInt("width",500),b.getInt("height",500)) 93 | .setShape(b.getInt("shape")); 94 | }else{ 95 | try { 96 | Class clazz= (Class) Class.forName(b.getString("name")); 97 | Constructor constructor=clazz.getConstructor(int.class); 98 | bg= constructor.newInstance(b.getInt("param")); 99 | } catch (Exception e) { 100 | throw new RuntimeException("Please set INTENT_CROP_COVER with a object name extends ACropCoverDrawable",e); 101 | } 102 | } 103 | mCover.setBackgroundDrawable(bg); 104 | helper=new CropHelper().attractTo(mImage); 105 | helper.setCropPath(bg); 106 | } 107 | 108 | public void setOnReadyRunnable(Runnable runnable){ 109 | this.ready=runnable; 110 | } 111 | 112 | public void crop(String path) throws IOException { 113 | helper.cropAndSave(path); 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/imagechooser/crop/CropHelper.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser.crop; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Matrix; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.graphics.PointF; 10 | import android.graphics.PorterDuff; 11 | import android.graphics.PorterDuffXfermode; 12 | import android.graphics.Rect; 13 | import android.os.Build; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.view.ViewTreeObserver; 17 | import android.widget.ImageView; 18 | 19 | import java.io.File; 20 | import java.io.FileOutputStream; 21 | import java.io.IOException; 22 | 23 | 24 | /** 25 | * Description: 26 | */ 27 | public class CropHelper implements View.OnTouchListener { 28 | 29 | private static final String TAG = "Touch"; 30 | 31 | private Matrix matrix = new Matrix(); 32 | private Matrix savedMatrix = new Matrix(); 33 | private Rect limit; 34 | 35 | // We can be in one of these 3 states 36 | private final int NONE = 0; 37 | private final int DRAG = 1; 38 | private final int ZOOM = 2; 39 | private int mode = NONE; 40 | 41 | private PointF start = new PointF(); 42 | private PointF mid = new PointF(); 43 | private float oldDist = 1f; 44 | private ImageView imageView; 45 | private CropPath cropPath; 46 | 47 | public CropHelper(Rect limit){ 48 | this.limit=limit; 49 | } 50 | 51 | public CropHelper(){ 52 | 53 | } 54 | 55 | public CropHelper attractTo(final ImageView iv){ 56 | this.imageView=iv; 57 | iv.setOnTouchListener(new View.OnTouchListener() { 58 | @Override 59 | public boolean onTouch(View v, MotionEvent event) { 60 | iv.setOnTouchListener(CropHelper.this); 61 | matrix.set(iv.getImageMatrix()); 62 | iv.setScaleType(ImageView.ScaleType.MATRIX); 63 | iv.setImageMatrix(matrix); 64 | CropHelper.this.onTouch(v,event); 65 | return true; 66 | } 67 | }); 68 | return this; 69 | } 70 | 71 | public void setCropPath(CropPath cp){ 72 | this.cropPath=cp; 73 | } 74 | 75 | private float[] values=new float[9]; 76 | 77 | @Override 78 | public boolean onTouch(View v, MotionEvent event) { 79 | 80 | if(v!=null&&((ImageView) v).getDrawable()!=null){ 81 | ImageView view = (ImageView) v; 82 | Rect rect=view.getDrawable().getBounds(); 83 | //事件处理 84 | switch (event.getAction() & MotionEvent.ACTION_MASK) { 85 | //一个手指按下时,标记为移动模式 86 | case MotionEvent.ACTION_DOWN: 87 | matrix.set(view.getImageMatrix()); 88 | savedMatrix.set(matrix); 89 | start.set(event.getX(), event.getY()); 90 | mode = DRAG; 91 | break; 92 | //第二个手指按下时,标记为缩放模式 93 | case MotionEvent.ACTION_POINTER_DOWN: 94 | oldDist = distance(event); 95 | if (oldDist > 10f) { 96 | savedMatrix.set(matrix); 97 | midPoint(mid, event); 98 | mode = ZOOM; 99 | } 100 | break; 101 | case MotionEvent.ACTION_UP: 102 | case MotionEvent.ACTION_POINTER_UP: 103 | checkMatrix(rect); 104 | mode = NONE; 105 | break; 106 | //手指移动时,根据当前是移动模式还是缩放模式做相应处理 107 | case MotionEvent.ACTION_MOVE: 108 | if (mode == DRAG) { 109 | matrix.set(savedMatrix); 110 | matrix.postTranslate(event.getX() - start.x, event.getY() 111 | - start.y); 112 | } else if (mode == ZOOM) { 113 | float newDist = distance(event); 114 | if (newDist > 10f) { 115 | matrix.set(savedMatrix); 116 | float scale = newDist / oldDist; 117 | matrix.postScale(scale, scale, mid.x, mid.y); 118 | } 119 | } 120 | break; 121 | } 122 | view.setImageMatrix(matrix); 123 | } 124 | return true; 125 | } 126 | 127 | public Bitmap crop(){ 128 | if(imageView!=null&&cropPath!=null){ 129 | if(limit==null){ 130 | limit=cropPath.limit(); 131 | } 132 | Paint paint=new Paint(); 133 | paint.setAntiAlias(true); 134 | imageView.setDrawingCacheEnabled(true); 135 | Bitmap bmp=Bitmap.createBitmap(limit.width(),limit.height(), Bitmap.Config.ARGB_8888); 136 | Canvas canvas=new Canvas(bmp); 137 | canvas.drawColor(Color.TRANSPARENT); 138 | int lId=canvas.saveLayer(0,0,limit.width(),limit.height(),null,Canvas.ALL_SAVE_FLAG); 139 | Path path=new Path(); 140 | path.addPath(cropPath.path(),-limit.left,-limit.top); 141 | canvas.drawPath(path,paint); 142 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 143 | canvas.drawBitmap(imageView.getDrawingCache(),-limit.left,-limit.top,paint); 144 | paint.setXfermode(null); 145 | canvas.restoreToCount(lId); 146 | imageView.setDrawingCacheEnabled(false); 147 | return bmp; 148 | } 149 | return null; 150 | } 151 | 152 | public String cropAndSave(String path) throws IOException { 153 | Bitmap bmp=crop(); 154 | if(bmp==null)return null; 155 | File file=new File(path); 156 | if(!file.getParentFile().exists()){ 157 | boolean b=file.mkdirs(); 158 | if(!b)return null; 159 | } 160 | if(file.exists()){ 161 | boolean c=file.delete(); 162 | if(!c)return null; 163 | } 164 | FileOutputStream fos=new FileOutputStream(file); 165 | bmp.compress(Bitmap.CompressFormat.PNG,100,fos); 166 | fos.flush(); 167 | fos.close(); 168 | bmp.recycle(); 169 | return file.getAbsolutePath(); 170 | } 171 | 172 | private void checkMatrix(Rect rect){ 173 | if(limit==null&&cropPath!=null){ 174 | limit=cropPath.limit(); 175 | } 176 | if(limit!=null){ 177 | if(mode==ZOOM){ 178 | matrix.getValues(values); 179 | if(rect.width()*values[0]=limit.left){ 191 | matrix.postTranslate(limit.left-values[2],0); 192 | } 193 | matrix.getValues(values); 194 | if(values[2]+rect.width()*values[0]limit.top){ 199 | matrix.postTranslate(0,limit.top-values[5]); 200 | } 201 | matrix.getValues(values); 202 | if(values[5]+rect.height()*values[4] drawables; 26 | 27 | public IChooseDrawable(){ 28 | paint=new Paint(); 29 | paint.setAntiAlias(true); 30 | paint.setColor(0x88000000); 31 | drawables=new SparseArray<>(); 32 | } 33 | 34 | public Drawable get(int state){ 35 | if(drawables.indexOfKey(state)>=0){ 36 | return drawables.get(state); 37 | }else{ 38 | InDrawable drawable=new InDrawable(state); 39 | drawables.put(state,drawable); 40 | return drawable; 41 | } 42 | } 43 | 44 | public void clear(){ 45 | drawables.clear(); 46 | } 47 | 48 | public int getBaseline(Paint paint,int top,int bottom){ 49 | Paint.FontMetrics i=paint.getFontMetrics(); 50 | return (int) ((bottom+top-i.top-i.bottom)/2); 51 | } 52 | 53 | public abstract void draw(Canvas canvas,Paint paint,int state); 54 | 55 | private class InDrawable extends Drawable{ 56 | 57 | private int state=0; 58 | 59 | InDrawable(int state){ 60 | this.state=state; 61 | } 62 | 63 | @Override 64 | public void draw(@NonNull Canvas canvas) { 65 | IChooseDrawable.this.draw(canvas,paint,state); 66 | } 67 | 68 | @Override 69 | public void setAlpha(int alpha) { 70 | 71 | } 72 | 73 | @Override 74 | public void setColorFilter(ColorFilter colorFilter) { 75 | 76 | } 77 | 78 | @Override 79 | public int getOpacity() { 80 | return PixelFormat.TRANSPARENT; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/utils/DensityUtils.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.utils; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by wuwang on 2016/11/6 7 | */ 8 | 9 | public class DensityUtils { 10 | 11 | /** 12 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素) 13 | */ 14 | public static int dip2px(Context context, float dpValue) { 15 | final float scale = context.getResources().getDisplayMetrics().density; 16 | return (int) (dpValue * scale + 0.5f); 17 | } 18 | 19 | /** 20 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp 21 | */ 22 | public static int px2dip(Context context, float pxValue) { 23 | final float scale = context.getResources().getDisplayMetrics().density; 24 | return (int) (pxValue / scale + 0.5f); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.utils; 2 | 3 | import android.util.Log; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * Description: 9 | */ 10 | public class LogUtils { 11 | 12 | public static boolean DEBUG = true; 13 | public static String TAG="LOG"; 14 | 15 | public static void setDebug(boolean isDebug) { 16 | DEBUG = isDebug; 17 | } 18 | 19 | public static void d(String msg){ 20 | if(DEBUG) 21 | Log.d(TAG,msg); 22 | } 23 | 24 | public static void d(String tag, String msg) { 25 | if (DEBUG) 26 | Log.d(tag, msg); 27 | } 28 | 29 | public static void d(String tag, String msg,Throwable throwable) { 30 | if (DEBUG) 31 | Log.d(tag, msg,throwable); 32 | } 33 | 34 | public static void i(String msg){ 35 | if(DEBUG) 36 | Log.i(TAG,msg); 37 | } 38 | 39 | public static void i(String tag, String msg) { 40 | if (DEBUG) 41 | Log.i(tag, msg); 42 | } 43 | 44 | public static void w(String tag, String msg) { 45 | if (DEBUG) 46 | Log.w(tag, msg); 47 | } 48 | 49 | public static void w(String msg){ 50 | if(DEBUG) 51 | Log.w(TAG,msg); 52 | } 53 | 54 | public static void w(String tag, String msg,Throwable throwable) { 55 | if (DEBUG) 56 | Log.w(tag, msg,throwable); 57 | } 58 | 59 | public static void e(String msg){ 60 | if(DEBUG) 61 | Log.e(TAG,msg); 62 | } 63 | 64 | public static void e(String tag, String msg) { 65 | if (DEBUG) 66 | Log.e(tag, msg); 67 | } 68 | 69 | public static void e(String tag, String msg,Throwable throwable) { 70 | if (DEBUG) 71 | Log.e(tag, msg,throwable); 72 | } 73 | 74 | public static void v(String msg){ 75 | if(DEBUG) 76 | Log.v(TAG,msg); 77 | } 78 | 79 | public static void v(String tag, String msg) { 80 | if (DEBUG) 81 | Log.v(tag, msg); 82 | } 83 | 84 | public static void v(String tag, String msg,Throwable throwable) { 85 | if (DEBUG) 86 | Log.e(tag, msg,throwable); 87 | } 88 | 89 | public static void eLogMap(String tag,Map map){ 90 | if(DEBUG){ 91 | for (Map.Entry entry:map.entrySet()) { 92 | if(entry!=null){ 93 | Log.e(tag,entry.getKey()+":"+entry.getValue()); 94 | } 95 | } 96 | } 97 | } 98 | 99 | } 100 | 101 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/widget/SquareImageView.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | /** 8 | * Created by wuwang on 2016/11/6 9 | */ 10 | 11 | public class SquareImageView extends ImageView { 12 | public SquareImageView(Context context) { 13 | super(context); 14 | } 15 | 16 | public SquareImageView(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) { 21 | super(context, attrs, defStyleAttr); 22 | } 23 | 24 | @Override 25 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 26 | super.onMeasure(widthMeasureSpec, widthMeasureSpec); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chooser/src/main/java/com/wuwang/widget/SquareRelativeLayout.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.RelativeLayout; 6 | 7 | /** 8 | * Description: 9 | */ 10 | public class SquareRelativeLayout extends RelativeLayout { 11 | 12 | public SquareRelativeLayout(Context context) { 13 | super(context); 14 | } 15 | 16 | public SquareRelativeLayout(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { 21 | super(context, attrs, defStyleAttr); 22 | } 23 | 24 | @Override 25 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 26 | super.onMeasure(widthMeasureSpec, widthMeasureSpec); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chooser/src/main/res/drawable/image_chooser_folder_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /chooser/src/main/res/drawable/left_back.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_activity_crop.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_activity_entry.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_default_title.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_fragment_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_fragment_crop.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 14 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_fragment_folder.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_item_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 24 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_item_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /chooser/src/main/res/layout/image_chooser_item_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 17 | -------------------------------------------------------------------------------- /chooser/src/main/res/menu/menu_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 10 | -------------------------------------------------------------------------------- /chooser/src/main/res/menu/menu_crop.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | -------------------------------------------------------------------------------- /chooser/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/chooser/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /chooser/src/main/res/mipmap-xhdpi/image_chooser_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/chooser/src/main/res/mipmap-xhdpi/image_chooser_back.png -------------------------------------------------------------------------------- /chooser/src/main/res/mipmap-xhdpi/image_chooser_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/chooser/src/main/res/mipmap-xhdpi/image_chooser_camera.png -------------------------------------------------------------------------------- /chooser/src/main/res/mipmap-xhdpi/image_chooser_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/chooser/src/main/res/mipmap-xhdpi/image_chooser_down.png -------------------------------------------------------------------------------- /chooser/src/main/res/mipmap-xhdpi/image_chooser_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/chooser/src/main/res/mipmap-xhdpi/image_chooser_placeholder.png -------------------------------------------------------------------------------- /chooser/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFFFF 4 | #FFDDDDDD 5 | #FFFF8800 6 | 7 | #FF25c2e6 8 | 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /chooser/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ImageChooser 3 | 相册 4 | 确定 5 | 6 | 7 | -------------------------------------------------------------------------------- /chooser/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /chooser/src/test/java/com/wuwang/imagechooser/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.wuwang.imagechooser; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doggycoder/ImageChooser/da0385175adde6ae50de7cf55d66ebb0785654c2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 说明 2 | 项目功能为图片选择器,当前已有功能及后续计划见更新说明,如有其它建议和意见,请mail至1558183202@qq.com。 3 | 围绕此项目写的相关博客:[相册基本实现](http://blog.csdn.net/junzia/article/details/53091606)、[图片裁剪](http://blog.csdn.net/junzia/article/details/52950210) 4 | ## 简单使用示例 5 | 如需使用图片选择器功能,将chooser加入为依赖工程,然后使用指定功能: 6 | ### 选择单张图片 7 | 如果需要选择单张图片,调用: 8 | ```java 9 | Intent intent=new Intent(IcFinal.ACTION_ALBUM); 10 | intent.putExtra(IcFinal.INTENT_MAX_IMG,1); 11 | startActivityForResult(intent,1); 12 | ``` 13 | ### 选择多张图片 14 | 多选时,只需将IcFinal.INTENT_MAX_IMG的值设置你需要的值即可: 15 | ```java 16 | Intent intent=new Intent(IcFinal.ACTION_ALBUM); 17 | intent.putExtra(IcFinal.INTENT_MAX_IMG,9); 18 | startActivityForResult(intent,1); 19 | ``` 20 | 如果你需要支持选择完成后,可以再次对之前选择的内容做修改,你可以增加: 21 | ```java 22 | intent.putStringArrayListExtra(IcFinal.INTENT_EXIST_DATA,data); //data为你之前所选的图片路径的ArrayList 23 | ``` 24 | ### 裁剪 25 | 如果需要选择单张图片并且裁剪,调用: 26 | ```java 27 | Intent intent=new Intent(IcFinal.ACTION_ALBUM); 28 | intent.putExtra(IcFinal.INTENT_IS_CROP,true); 29 | startActivityForResult(intent,1); 30 | ``` 31 | 默认为圆形图片,大小为500*500。如果需要自行设定,给intent增加以下参数: 32 | ```java 33 | intent.putExtra(IcFinal.INTENT_CROP_SHAPE,CropPath.SHAPE_RECT); //矩形,默认为CropPath.SHAPE_CIRCEL圆形 34 | intent.putExtra(IcFinal.INTENT_CROP_WIDTH,512); //裁剪宽度 35 | intent.putExtra(IcFinal.INTENT_CROP_HEIGHT,280); //裁剪高度 36 | ``` 37 | 或者,你要的是其他不规则的形状,那么你可以选择继承ACropCoverDrawable类,自己来控制你需要的裁剪形状,然后使用以下代码来启动裁剪: 38 | ```java 39 | Intent intent=new Intent(IcFinal.ACTION_ALBUM); 40 | intent.putExtra(IcFinal.INTENT_IS_CROP,true); 41 | intent.putExtra(IcFinal.INTENT_CROP_COVER,ExampleCropPath.class.getName()); 42 | intent.putExtra(IcFinal.INTENT_CROP_PARAM,1); //参数 43 | startActivityForResult(intent,1); 44 | ``` 45 | 你所实现的ACropCoverDrawable类,只能使用一个int参数来控制它的反射出来的实体。其实一个int已经可以做很多事了。 46 | 47 | ## 更多设置 48 | 也许图片选择器默认的UI不符合你的要求,你可以选择利用ChooserSetting中的静态参数来更改图片选择器的效果: 49 | ```java 50 | /**标题的背景颜色*/ 51 | public static int TITLE_COLOR=0xFF584512; 52 | /**图片选择页,每行显示数*/ 53 | public static int NUM_COLUMNS=3; 54 | /**图片加载失败的图片*/ 55 | public static int errorResId=0; 56 | /**图片加载的占位图片*/ 57 | public static int placeResId=R.mipmap.image_chooser_placeholder; 58 | /**图片加载的动画*/ 59 | public static int loadAnimateResId=0; 60 | /**选中图片的滤镜颜色*/ 61 | public static int chooseFilter=0x55000000; 62 | /**未被选中的图片的滤镜颜色*/ 63 | public static int unChooseFilter=0; 64 | /**最新的图片集合显示名字*/ 65 | public static String newestAlbumName="最新图片"; 66 | /**最新图片集合的最大数量*/ 67 | public static int newestAlbumSize=100; 68 | public static int albumPopupHeight=600; 69 | public static String tantoToast=""; 70 | /**照片选择指示器*/ 71 | public static IChooseDrawable chooseDrawable=new CircleChooseDrawable(true,0xFF25c2e6); 72 | ``` 73 | 如果这些也无法满足你的UI要求,你也可以参照EntryActivity重新写相册的入口Activity,参照CropActivity重写裁剪的入口Activity。 74 | 75 | # 更新说明 76 | 77 | ## 已完成功能 78 | 1. 图片单选多选功能 79 | 2. 多图选择指示器 80 | 3. 图片裁剪功能 81 | 4. 拍照功能 82 | 5. 裁剪形状的完全定制 83 | 84 | ## 待完成工作 85 | 1. ~~图片单选多选~~ 86 | 2. ~~多图选择指示器~~ 87 | 3. ~~图片裁剪~~ 88 | 4. ~~裁剪形状的完全定制~~ 89 | 4. 多图选择时的大图浏览 90 | 5. ~~拍照功能~~ 91 | 6. UI让使用者可高度定制 92 | 7. 加入到jcenter和maven 93 | 8. 拍照的美颜及其他滤镜 94 | 95 | ## 20161111更新 96 | 基本完成相册选择、拍照、裁剪功能 97 | 98 | ## 20161113更新 99 | 1. 实现裁剪形状的完全定制入口 100 | 2. 完成对多选后再次修改的支持 101 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':chooser' 2 | --------------------------------------------------------------------------------