├── .idea ├── .name ├── copyright │ └── profiles_settings.xml ├── vcs.xml ├── modules.xml ├── gradle.xml ├── compiler.xml └── misc.xml ├── app ├── .gitignore ├── libs │ └── uil.jar ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable-xhdpi │ │ │ │ ├── back.png │ │ │ │ ├── icon_go.png │ │ │ │ ├── icon_back2.png │ │ │ │ ├── post_add_pic.png │ │ │ │ ├── progress_icon.png │ │ │ │ ├── album_finish.9.png │ │ │ │ ├── albumset_selected.png │ │ │ │ ├── btn_posts_camera_l.png │ │ │ │ ├── post_pager_delete.png │ │ │ │ ├── albumset_preselected.png │ │ │ │ └── dangkr_no_picture_small.png │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── standard_color.xml │ │ │ │ ├── standard_dimens.xml │ │ │ │ ├── styles.xml │ │ │ │ ├── colors.xml │ │ │ │ └── dimens.xml │ │ │ ├── drawable │ │ │ │ ├── white_gray_bg_selector.xml │ │ │ │ └── picture_setting_album_checkbox.xml │ │ │ ├── menu │ │ │ │ └── menu_main.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── anim │ │ │ │ └── rotate_loading.xml │ │ │ └── layout │ │ │ │ ├── simple_list_item.xml │ │ │ │ ├── item_albumfoler.xml │ │ │ │ ├── item_album_pager.xml │ │ │ │ ├── album_item_header_bar.xml │ │ │ │ ├── local_album.xml │ │ │ │ ├── local_album_detail.xml │ │ │ │ └── post_dynamic.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── example │ │ │ └── localalbum │ │ │ ├── ui │ │ │ ├── BaseActivity.java │ │ │ ├── LocalAlbum.java │ │ │ ├── DynamicPost.java │ │ │ └── LocalAlbumDetail.java │ │ │ ├── widget │ │ │ ├── FilterImageView.java │ │ │ ├── AlbumViewPager.java │ │ │ └── MatrixImageView.java │ │ │ ├── common │ │ │ ├── MethodsCompat.java │ │ │ ├── ExtraKey.java │ │ │ ├── StringUtils.java │ │ │ ├── LocalImageHelper.java │ │ │ └── ImageUtils.java │ │ │ ├── AppManager.java │ │ │ └── AppContext.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── example │ │ └── localalbum │ │ └── ApplicationTest.java ├── proguard-rules.pro ├── build.gradle └── app.iml ├── settings.gradle ├── README.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── LocalAlbum.iml ├── gradlew.bat └── gradlew /.idea/.name: -------------------------------------------------------------------------------- 1 | LocalAlbum -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/libs/uil.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/libs/uil.jar -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LocalAlbum 2 | 本地相册,遍历本地图片,支持多选图片功能。 3 | 博客地址 http://www.cnblogs.com/linjzong/p/4629800.html 4 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/icon_go.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/icon_back2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/icon_back2.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/post_add_pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/post_add_pic.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/progress_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/progress_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/album_finish.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/album_finish.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/albumset_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/albumset_selected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/btn_posts_camera_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/btn_posts_camera_l.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/post_pager_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/post_pager_delete.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/albumset_preselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/albumset_preselected.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/dangkr_no_picture_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinJZong/LocalAlbum/HEAD/app/src/main/res/drawable-xhdpi/dangkr_no_picture_small.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LocalAlbum 3 | 4 | Hello world! 5 | Settings 6 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 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.2.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/white_gray_bg_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/picture_setting_album_checkbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/localalbum/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/values/standard_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #333333 4 | #666666 5 | #999999 6 | #ffcccccc 7 | #ffeeeeee 8 | #ffffffff 9 | #15aeed 10 | #546893 11 | #6a7989 12 | -------------------------------------------------------------------------------- /app/src/main/res/anim/rotate_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /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 /Users/linjizong/SDK/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/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion '21.1.2' 6 | 7 | defaultConfig { 8 | applicationId "com.example.localalbum" 9 | minSdkVersion 15 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.2.0' 25 | compile files('libs/uil.jar') 26 | } 27 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /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 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /app/src/main/res/layout/simple_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 14 | 15 | 24 | -------------------------------------------------------------------------------- /LocalAlbum.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/standard_dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2.0dip 4 | 3.0dip 5 | 5.0dip 6 | 10.0dip 7 | 15.0dip 8 | 20.0dip 9 | 0.5dip 10 | 1dip 11 | 5dip 12 | 10dip 13 | 14 | 10dip 15 | 11dip 16 | 12dip 17 | 13dip 18 | 14dip 19 | 15.0dip 20 | 16dip 21 | 17dip 22 | 18.0dip 23 | 18dip 24 | 18dip 25 | 100dip 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_albumfoler.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 28 | 35 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 1.7 27 | 28 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 15 | 16 | 23 | 29 | 30 | 36 | 37 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/ui/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.ui; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.content.pm.ActivityInfo; 6 | import android.os.Bundle; 7 | import android.os.Handler; 8 | import android.os.Message; 9 | import android.view.Window; 10 | 11 | import com.example.localalbum.AppContext; 12 | import com.example.localalbum.AppManager; 13 | 14 | 15 | /** 16 | * @Description:Activity基类 17 | * @author linjizong 18 | * @date 2015-3-18 19 | */ 20 | 21 | /** 22 | * @Description: 23 | * @author linjizong 24 | * @date 2015-3-30 25 | */ 26 | public class BaseActivity extends Activity { 27 | //应用是否销毁标志 28 | protected boolean isDestroy; 29 | //防止重复点击设置的标志,涉及到点击打开其他Activity时,将该标志设置为false,在onResume事件中设置为true 30 | private boolean clickable=true; 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | isDestroy=false; 35 | //设置无标题 36 | requestWindowFeature(Window.FEATURE_NO_TITLE); 37 | //垂直显示 38 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 39 | // 添加Activity到堆栈 40 | AppManager.getAppManager().addActivity(this); 41 | } 42 | 43 | @Override 44 | protected void onDestroy() { 45 | super.onDestroy(); 46 | isDestroy=true; 47 | // 结束Activity&从堆栈中移除 48 | AppManager.getAppManager().finishActivity(this); 49 | } 50 | 51 | @Override 52 | protected void onResume() { 53 | super.onResume(); 54 | //每次返回界面时,将点击标志设置为可点击 55 | clickable=true; 56 | } 57 | 58 | /** 59 | * 当前是否可以点击 60 | * @return 61 | */ 62 | protected boolean isClickable(){ 63 | return clickable; 64 | } 65 | 66 | /** 67 | * 锁定点击 68 | */ 69 | protected void lockClick(){ 70 | clickable=false; 71 | } 72 | 73 | 74 | 75 | @Override 76 | public void startActivityForResult(Intent intent, int requestCode, Bundle options) { 77 | if(isClickable()) { 78 | lockClick(); 79 | super.startActivityForResult(intent, requestCode,options); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/widget/FilterImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.PorterDuff; 6 | import android.graphics.drawable.Drawable; 7 | import android.util.AttributeSet; 8 | import android.view.MotionEvent; 9 | import android.widget.ImageView; 10 | 11 | 12 | /** 13 | * @ClassName: ThumbnailView 14 | * @Description: 点击时显示明暗变化(滤镜效果)的ImageView 15 | * @author LinJ 16 | * @date 2015-1-6 下午2:13:46 17 | * 18 | */ 19 | public class FilterImageView extends ImageView{ 20 | public FilterImageView(Context context){ 21 | super(context); 22 | } 23 | public FilterImageView(Context context, AttributeSet attrs) { 24 | super(context, attrs); 25 | // TODO Auto-generated constructor stub 26 | } 27 | public FilterImageView(Context context, AttributeSet attrs, int defStyle) { 28 | super(context, attrs, defStyle); 29 | 30 | } 31 | @Override 32 | public boolean onTouchEvent(MotionEvent event) { 33 | switch (event.getActionMasked()) { 34 | case MotionEvent.ACTION_DOWN: 35 | //在按下事件中设置滤镜 36 | setFilter(); 37 | break; 38 | case MotionEvent.ACTION_UP: 39 | //由于捕获了Touch事件,需要手动触发Click事件 40 | performClick(); 41 | case MotionEvent.ACTION_CANCEL: 42 | //在CANCEL和UP事件中清除滤镜 43 | removeFilter(); 44 | break; 45 | default: 46 | break; 47 | } 48 | return true; 49 | } 50 | 51 | /** 52 | * 设置滤镜 53 | */ 54 | private void setFilter() { 55 | //先获取设置的src图片 56 | Drawable drawable=getDrawable(); 57 | //当src图片为Null,获取背景图片 58 | if (drawable==null) { 59 | drawable=getBackground(); 60 | } 61 | if(drawable!=null){ 62 | //设置滤镜 63 | drawable.setColorFilter(Color.GRAY,PorterDuff.Mode.MULTIPLY);; 64 | } 65 | } 66 | /** 67 | * 清除滤镜 68 | */ 69 | private void removeFilter() { 70 | //先获取设置的src图片 71 | Drawable drawable=getDrawable(); 72 | //当src图片为Null,获取背景图片 73 | if (drawable==null) { 74 | drawable=getBackground(); 75 | } 76 | if(drawable!=null){ 77 | //清除滤镜 78 | drawable.clearColorFilter(); 79 | } 80 | } 81 | 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/common/MethodsCompat.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.common; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.content.ContentResolver; 6 | import android.content.Context; 7 | import android.graphics.Bitmap; 8 | import android.graphics.BitmapFactory.Options; 9 | import android.graphics.Paint; 10 | import android.os.Build; 11 | import android.provider.MediaStore; 12 | import android.view.View; 13 | import android.view.Window; 14 | 15 | import java.io.File; 16 | 17 | /** 18 | * Android各版本的兼容方法 19 | * @author liux (http://my.oschina.net/liux) 20 | * @version 1.0 21 | * @created 2012-8-6 22 | */ 23 | public class MethodsCompat { 24 | 25 | @TargetApi(5) 26 | public static void overridePendingTransition(Activity activity, int enter_anim, int exit_anim) { 27 | activity.overridePendingTransition(enter_anim, exit_anim); 28 | } 29 | 30 | @TargetApi(7) 31 | public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind, Options options) { 32 | return MediaStore.Images.Thumbnails.getThumbnail(cr,origId,kind, options); 33 | } 34 | 35 | @TargetApi(8) 36 | public static File getExternalCacheDir(Context context) { 37 | 38 | // // return context.getExternalCacheDir(); API level 8 39 | // 40 | // // e.g. "/Android/data//cache/" 41 | // final File extCacheDir = new File(Environment.getExternalStorageDirectory(), 42 | // "/Android/data/" + context.getApplicationInfo().packageName + "/cache/"); 43 | // extCacheDir.mkdirs(); 44 | // return extCacheDir; 45 | 46 | return context.getExternalCacheDir(); 47 | } 48 | 49 | @TargetApi(11) 50 | public static void recreate(Activity activity) { 51 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 52 | activity.recreate(); 53 | } 54 | } 55 | 56 | @TargetApi(11) 57 | public static void setLayerType(View view, int layerType, Paint paint) { 58 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 59 | view.setLayerType(layerType, paint); 60 | } 61 | } 62 | 63 | @TargetApi(14) 64 | public static void setUiOptions(Window window, int uiOptions) { 65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 66 | window.setUiOptions(uiOptions); 67 | } 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/common/ExtraKey.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.common; 2 | 3 | /** 4 | * @Description: 界面跳转时 传递的key 命名方式为:来源Activity_目标Activity_KEY名称 5 | * @author linjizong 6 | * @date 2015-3-24 7 | */ 8 | public class ExtraKey { 9 | 10 | public static final String USERINFO_EDIT_TITLE="title";//标题 11 | public static final String USERINFO_EDIT_VALUE="value";//内容 12 | public static final String USER_PROPERTYKEY="key";//在property文件中得key 13 | public static final String USERINFO_EDIT_NUMBER="number";//输入格式是否位数字 14 | public static final String USERINFO_MAX_LENGTH="max";//输入最大长度 15 | public static final String EDIT_USERINFO_VALUE="value";//修改后返回的值 16 | public static final String SELECTINTEREST_USERINFO_VALUE="interest";//选择爱好后返回的值 17 | public static final String PROVINCE_CITY_NAME="province";//当前选择的省份 18 | public static final String CLUB_CLUBINFO_ID="clubid";//当前选择的俱乐部ID 19 | public static final String STATUS="status";//状态码,不同状态代表不同请求.0:关注 1:粉丝 2:想去 3:已报名 20 | public static final String MAIN_POSITION="position";//主界面当前标签位置,主要用以登录时切换到“我的”界面 21 | public static final String USERINFO_SIGNTURE = "signture"; 22 | 23 | public static final String BROWSER_TITLE="browser_title";//浏览器标题 24 | public static final String BROWSER_URL="browser_url";//浏览器链接 25 | 26 | public static final String ACTIVITY_ID="activity_id";//活动ID 27 | public static final String CLUB_ID="club_id";//俱乐部ID 28 | 29 | public static final String FROM_ACTIVITY="from_activity";//在地区选择界面使用,标记是否从activity界面进入 30 | public static final String URL_ARRAYLIST="url_arraylist";//图片查看界面的url数组 31 | public static final String URL_ARRAYLIST_ACTIVE="url_arraylist_active";//当前选择的图片 32 | 33 | public static final String ACTIVITY_TYPE="activity_type";//活动类型:想去或带领的活动 34 | public static final String ACTIVITY_STATUS="activity_status";//活动状态:进行中或已结束 35 | 36 | public static final String DANGKR_TYPE="dangkr_type";//荡客界面跳转到列表界面时的请求类型 37 | public static final String DANGKR_TITLE="dangkr_title";//荡客界面跳转到列表界面时的标题 38 | public static final String HOME_PAGE_ID="home_page_id";//跳转到个人主页传递的人物ID 39 | public static final String HOME_PAGE_IS_LEADER="home_page_is_leader";//个人主页是否领队 40 | 41 | public static final String USER_ID="user_id";//跳转到动态界面的人物ID 42 | public static final String USER_NAME="user_name";//跳转到动态界面传递的人物名称 43 | public static final String LOCAL_FOLDER_NAME="local_folder_name";//跳转到相册页的文件夹名称 44 | 45 | public static final String DYNAMIC_ID_AND_DATE="dynamic_id_and_date";//动态ID和时间戳字符串 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/AppManager.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | 6 | 7 | import java.util.Stack; 8 | 9 | 10 | /** 11 | * @Description:Activity管理类 12 | * @author linjizong 13 | * @date 2015-4-11 14 | */ 15 | public class AppManager { 16 | private static Stack activityStack; 17 | private static AppManager instance; 18 | private AppManager(){} 19 | /** 20 | * 单一实例 21 | */ 22 | public static AppManager getAppManager(){ 23 | if(instance==null){ 24 | instance=new AppManager(); 25 | } 26 | return instance; 27 | } 28 | /** 29 | * 添加Activity到堆栈 30 | */ 31 | public void addActivity(Activity activity){ 32 | if(activityStack==null){ 33 | activityStack=new Stack(); 34 | } 35 | activityStack.add(activity); 36 | } 37 | /** 38 | * 获取当前Activity(堆栈中最后一个压入的) 39 | */ 40 | public Activity currentActivity(){ 41 | Activity activity=activityStack.lastElement(); 42 | return activity; 43 | } 44 | /** 45 | * 结束当前Activity(堆栈中最后一个压入的) 46 | */ 47 | public void finishActivity(){ 48 | Activity activity=activityStack.lastElement(); 49 | finishActivity(activity); 50 | } 51 | /** 52 | * 结束指定的Activity 53 | */ 54 | public void finishActivity(Activity activity){ 55 | // //应用即将全部关闭,清理缓存 56 | // if(activityStack.size()==1){ 57 | // ((AppContext)activity.getApplication()).clearWebViewCache(); 58 | // 59 | // } 60 | if(activity!=null){ 61 | activityStack.remove(activity); 62 | activity.finish(); 63 | activity=null; 64 | } 65 | } 66 | /** 67 | * 结束指定类名的Activity 68 | */ 69 | public void finishActivity(Class cls){ 70 | for (Activity activity : activityStack) { 71 | if(activity.getClass().equals(cls) ){ 72 | finishActivity(activity); 73 | } 74 | } 75 | } 76 | //获取指定类名的Activity 77 | public Activity getActivity(Class cls){ 78 | for (Activity activity : activityStack) { 79 | if(activity.getClass().equals(cls) ){ 80 | return activity ; 81 | } 82 | } 83 | return null; 84 | } 85 | 86 | /** 87 | * 结束所有Activity 88 | */ 89 | public void finishAllActivity(){ 90 | for (int i = 0, size = activityStack.size(); i < size; i++){ 91 | if (null != activityStack.get(i)){ 92 | activityStack.get(i).finish(); 93 | } 94 | } 95 | activityStack.clear(); 96 | } 97 | /** 98 | * 退出应用程序 99 | */ 100 | public void AppExit(Context context) { 101 | try { 102 | finishAllActivity(); 103 | System.exit(0); 104 | } catch (Exception e) { } 105 | } 106 | 107 | 108 | 109 | 110 | 111 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/layout/album_item_header_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 22 | 23 | 34 | 35 | 45 | 46 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 24 | 25 | 26 | 35 | 36 | 37 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/local_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 24 | 25 | 34 | 35 | 43 | 44 | 45 | 46 | 47 | 48 | 55 | 56 | 62 | 63 | 70 | 71 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/AppContext.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.view.Display; 6 | import android.view.WindowManager; 7 | 8 | import com.example.localalbum.common.LocalImageHelper; 9 | import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; 10 | import com.nostra13.universalimageloader.core.ImageLoader; 11 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 12 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType; 13 | import com.nostra13.universalimageloader.core.download.BaseImageDownloader; 14 | 15 | import java.io.File; 16 | 17 | // 18 | 19 | /** 20 | * 全局应用程序类:用于保存和调用全局应用配置及访问网络数据 21 | * 22 | * @author linjizong 23 | * @created 2015-3-22 24 | */ 25 | public class AppContext extends Application { 26 | private static final String TAG = AppContext.class.getSimpleName(); 27 | private static final String APP_CACAHE_DIRNAME = "/webcache"; 28 | 29 | //singleton 30 | private static AppContext appContext = null; 31 | private Display display; 32 | 33 | 34 | 35 | @Override 36 | public void onCreate() { 37 | super.onCreate(); 38 | appContext = this; 39 | init(); 40 | } 41 | 42 | public static AppContext getInstance() { 43 | return appContext; 44 | } 45 | 46 | /** 47 | * 初始化 48 | */ 49 | private void init() { 50 | initImageLoader(getApplicationContext()); 51 | //本地图片辅助类初始化 52 | LocalImageHelper.init(this); 53 | if (display == null) { 54 | WindowManager windowManager = (WindowManager) 55 | getSystemService(Context.WINDOW_SERVICE); 56 | display = windowManager.getDefaultDisplay(); 57 | } 58 | } 59 | 60 | 61 | public static void initImageLoader(Context context) { 62 | ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(context); 63 | config.threadPriority(Thread.NORM_PRIORITY); 64 | config.denyCacheImageMultipleSizesInMemory(); 65 | config.memoryCacheSize((int) Runtime.getRuntime().maxMemory() / 4); 66 | config.diskCacheFileNameGenerator(new Md5FileNameGenerator()); 67 | config.diskCacheSize(100 * 1024 * 1024); // 100 MiB 68 | config.tasksProcessingOrder(QueueProcessingType.LIFO); 69 | //修改连接超时时间5秒,下载超时时间5秒 70 | config.imageDownloader(new BaseImageDownloader(appContext, 5 * 1000, 5 * 1000)); 71 | // config.writeDebugLogs(); // Remove for release app 72 | // Initialize ImageLoader with configuration. 73 | ImageLoader.getInstance().init(config.build()); 74 | } 75 | 76 | public String getCachePath() { 77 | File cacheDir; 78 | if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) 79 | cacheDir = getExternalCacheDir(); 80 | else 81 | cacheDir = getCacheDir(); 82 | if (!cacheDir.exists()) 83 | cacheDir.mkdirs(); 84 | return cacheDir.getAbsolutePath(); 85 | } 86 | /** 87 | * @return 88 | * @Description: 获取当前屏幕的宽度 89 | */ 90 | public int getWindowWidth() { 91 | return display.getWidth(); 92 | } 93 | 94 | /** 95 | * @return 96 | * @Description: 获取当前屏幕的高度 97 | */ 98 | public int getWindowHeight() { 99 | return display.getHeight(); 100 | } 101 | 102 | /** 103 | * @return 104 | * @Description: 获取当前屏幕一半宽度 105 | */ 106 | public int getHalfWidth() { 107 | return display.getWidth() / 2; 108 | } 109 | 110 | /** 111 | * @return 112 | * @Description: 获取当前屏幕1/4宽度 113 | */ 114 | public int getQuarterWidth() { 115 | return display.getWidth() / 4; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #ffffffff 5 | #ff363636 6 | #00000000 7 | #ffeeeeee 8 | #00000000 9 | #000000 10 | #c6c6c6 11 | #037BFF 12 | #FD4A2E 13 | #8F8F8F 14 | #aa111213 15 | #ffeeeeee 16 | #fffcfcfd 17 | 18 | 19 | #fffded 20 | #bdbdbd 21 | #3799df 22 | #ffffffff 23 | #646464 24 | #8f8f8f 25 | #cbcbcb 26 | 27 | 28 | #4da0e4 29 | #ffffff 30 | #e3f1fa 31 | 32 | 33 | #00adef 34 | #ffffff 35 | 36 | 37 | #f8f8f8 38 | #2c2c2c 39 | #1cb6f4 40 | 41 | 42 | #ffffff 43 | #d9d9d9 44 | #cacaca 45 | #333333 46 | #999999 47 | #f6f7fb 48 | #9c9f9d 49 | #6fbce6 50 | #e7e8ea 51 | #656565 52 | #e7e7e7 53 | #313131 54 | #707070 55 | #f54c61 56 | 57 | 58 | #333333 59 | #999999 60 | 61 | 62 | #333333 63 | #3e9de0 64 | 65 | 66 | #f6f7fb 67 | 68 | #999999 69 | #333333 70 | 71 | 72 | #20b2ee 73 | #0392cd 74 | #dedede 75 | 76 | 77 | #eeeeee 78 | #333333 79 | #536893 80 | 81 | #cccccc 82 | #666666 83 | 84 | #eeeeee 85 | 86 | 87 | #ffffff 88 | #eeeeee 89 | #eeeeee 90 | #b0b0b0 91 | #333333 92 | #f1f1f1 93 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12.0dip 5 | 12.0dip 6 | 45.0dip 7 | 10dip 8 | 10dip 9 | 15dip 10 | 0.5dip 11 | 50.0dip 12 | 13 | 14 | 15dip 15 | 44dip 16 | 20dip 17 | 25dip 18 | 15dip 19 | 15dip 20 | 15dip 21 | 20dip 22 | 75dip 23 | 24 | 40dip 25 | 15dip 26 | 18dip 27 | 15dip 28 | 20dip 29 | 45dip 30 | 4dip 31 | 32 | 33 | 45dip 34 | 20dip 35 | 25dip 36 | 20dip 37 | 90dip 38 | 40dip 39 | 15dip 40 | 41 | 42 | 55dip 43 | 8dip 44 | 4dip 45 | 3dip 46 | 47 | 48 | 15dip 49 | 150dip 50 | 36dip 51 | 6dip 52 | 65dip 53 | 25dip 54 | 50dip 55 | 41dip 56 | 30dip 57 | 15dip 58 | 15dip 59 | 180dip 60 | 30dip 61 | 80dip 62 | 60dip 63 | 20dip 64 | 5dip 65 | 30dip 66 | 18dip 67 | 10dip 68 | 6dip 69 | 8dip 70 | 5dip 71 | 140dip 72 | 90dip 73 | 77dip 74 | 28dip 75 | 76 | 77 | 95dip 78 | 50dip 79 | 18dip 80 | 25dip 81 | 82 | 83 | 65dip 84 | 45dip 85 | 86 | 87 | 190dip 88 | 89 | 90 | 10dip 91 | 20dip 92 | 50dip 93 | 94 | 95 | 35dip 96 | 10dip 97 | 55dip 98 | 15dip 99 | 100 | 101 | 44dip 102 | 27dip 103 | 104 | 105 | 190dip 106 | 80dip 107 | 10dip 108 | 60dip 109 | 110 | 200dip 111 | 112 | 113 | 12dip 114 | 15sp 115 | 45dip 116 | 117 | -------------------------------------------------------------------------------- /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 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /app/src/main/res/layout/local_album_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 24 | 25 | 37 | 38 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 67 | 68 | 73 | 74 | 79 | 80 | 85 | 86 | 95 | 96 | 107 | 108 | 121 | 122 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /app/src/main/res/layout/post_dynamic.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 15 | 16 | 21 | 22 | 31 | 32 | 40 | 41 | 52 | 53 | 54 | 58 | 59 | 72 | 73 | 84 | 85 | 92 | 93 | 100 | 101 | 106 | 107 | 108 | 109 | 120 | 121 | 125 | 126 | 127 | 132 | 133 | 138 | 139 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/widget/AlbumViewPager.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.widget; 2 | 3 | 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.support.v4.view.PagerAdapter; 7 | import android.support.v4.view.ViewPager; 8 | import android.util.AttributeSet; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.TextView; 13 | 14 | import com.example.localalbum.R; 15 | import com.example.localalbum.common.LocalImageHelper; 16 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 17 | import com.nostra13.universalimageloader.core.ImageLoader; 18 | import com.nostra13.universalimageloader.core.assist.FailReason; 19 | import com.nostra13.universalimageloader.core.assist.ImageScaleType; 20 | import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; 21 | import com.nostra13.universalimageloader.core.imageaware.ImageViewAware; 22 | import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; 23 | import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener; 24 | 25 | import java.util.List; 26 | 27 | 28 | /** 29 | * @ClassName: AlbumViewPager 30 | * @Description: 自定义viewpager 优化了事件拦截 31 | * @author LinJ 32 | * @date 2015-1-9 下午5:33:33 33 | * 34 | */ 35 | public class AlbumViewPager extends ViewPager implements MatrixImageView.OnMovingListener { 36 | public final static String TAG="AlbumViewPager"; 37 | 38 | 39 | /** 当前子控件是否处理拖动状态 */ 40 | private boolean mChildIsBeingDragged=false; 41 | 42 | /** 界面单击事件 用以显示和隐藏菜单栏 */ 43 | private MatrixImageView.OnSingleTapListener onSingleTapListener; 44 | DisplayImageOptions options; 45 | //本地图片的option 46 | DisplayImageOptions localOptions; 47 | 48 | private class ProcressListener implements ImageLoadingProgressListener { 49 | private View mView = null; 50 | 51 | public ProcressListener(View view){ 52 | this.mView = view; 53 | } 54 | @Override 55 | public void onProgressUpdate(String arg0, View view, int current, int total) { 56 | TextView loadText = (TextView) mView.findViewById(R.id.current_procress); 57 | loadText.setText(String.valueOf(100 * current / total) + "%"); 58 | loadText.bringToFront(); 59 | } 60 | 61 | } 62 | 63 | 64 | private ImageLoadingListener loadingListenerr = new ImageLoadingListener(){ 65 | 66 | @Override 67 | public void onLoadingCancelled(String arg0, View arg1) { 68 | } 69 | 70 | @Override 71 | public void onLoadingComplete(String arg0, View view, Bitmap arg2) { 72 | view.setVisibility(View.VISIBLE); 73 | view.getParent().bringChildToFront(view); 74 | } 75 | 76 | @Override 77 | public void onLoadingFailed(String arg0, View view, FailReason arg2) { 78 | // view.setVisibility(View.VISIBLE); 79 | // view.getParent().bringChildToFront(view); 80 | } 81 | 82 | @Override 83 | public void onLoadingStarted(String arg0, View arg1) { 84 | } 85 | 86 | }; 87 | 88 | 89 | 90 | 91 | 92 | /** 播放按钮点击事件 */ 93 | public AlbumViewPager(Context context, AttributeSet attrs) { 94 | super(context, attrs); 95 | localOptions=new DisplayImageOptions.Builder() 96 | .cacheInMemory(true) 97 | .cacheOnDisk(false) 98 | .bitmapConfig(Bitmap.Config.RGB_565) 99 | .imageScaleType(ImageScaleType.EXACTLY) 100 | .displayer(new SimpleBitmapDisplayer()).build(); 101 | //DisplayImageOptions.getDefaltOpitions(0, R.drawable.dangkr_no_picture, 102 | //((AppContext)context.getApplicationContext()).getWindowWidth()); 103 | } 104 | 105 | 106 | 107 | 108 | 109 | 110 | @Override 111 | public boolean onInterceptTouchEvent(MotionEvent arg0) { 112 | if(mChildIsBeingDragged) 113 | return false; 114 | return super.onInterceptTouchEvent(arg0); 115 | } 116 | 117 | @Override 118 | public void startDrag() { 119 | // TODO Auto-generated method stub 120 | mChildIsBeingDragged=true; 121 | } 122 | 123 | 124 | @Override 125 | public void stopDrag() { 126 | // TODO Auto-generated method stub 127 | mChildIsBeingDragged=false; 128 | } 129 | 130 | public void setOnSingleTapListener(MatrixImageView.OnSingleTapListener onSingleTapListener) { 131 | this.onSingleTapListener = onSingleTapListener; 132 | } 133 | 134 | public class ViewPagerAdapter extends PagerAdapter { 135 | private List paths;//大图地址 如果为网络图片 则为大图url 136 | public ViewPagerAdapter(List paths){ 137 | this.paths=paths; 138 | } 139 | 140 | @Override 141 | public int getCount() { 142 | return paths.size(); 143 | } 144 | 145 | @Override 146 | public Object instantiateItem(ViewGroup viewGroup, int position) { 147 | //注意,这里不可以加inflate的时候直接添加到viewGroup下,而需要用addView重新添加 148 | //因为直接加到viewGroup下会导致返回的view为viewGroup 149 | View imageLayout = inflate(getContext(),R.layout.item_album_pager, null); 150 | viewGroup.addView(imageLayout); 151 | assert imageLayout != null; 152 | MatrixImageView imageView = (MatrixImageView) imageLayout.findViewById(R.id.image); 153 | imageView.setOnMovingListener(AlbumViewPager.this); 154 | imageView.setOnSingleTapListener(onSingleTapListener); 155 | String path=paths.get(position); 156 | ImageLoader.getInstance().displayImage(path, imageView, localOptions, loadingListenerr, new ProcressListener(imageLayout)); 157 | return imageLayout; 158 | } 159 | 160 | 161 | 162 | @Override 163 | public int getItemPosition(Object object) { 164 | //在notifyDataSetChanged时返回None,重新绘制 165 | return POSITION_NONE; 166 | } 167 | 168 | @Override 169 | public void destroyItem(ViewGroup container, int arg1, Object object) { 170 | ((ViewPager) container).removeView((View) object); 171 | } 172 | 173 | @Override 174 | public boolean isViewFromObject(View arg0, Object arg1) { 175 | return arg0 == arg1; 176 | } 177 | 178 | 179 | } 180 | 181 | public class LocalViewPagerAdapter extends PagerAdapter { 182 | private List paths;//大图地址 如果为网络图片 则为大图url 183 | public LocalViewPagerAdapter(List paths){ 184 | this.paths=paths; 185 | } 186 | 187 | @Override 188 | public int getCount() { 189 | return paths.size(); 190 | } 191 | 192 | @Override 193 | public Object instantiateItem(ViewGroup viewGroup, int position) { 194 | //注意,这里不可以加inflate的时候直接添加到viewGroup下,而需要用addView重新添加 195 | //因为直接加到viewGroup下会导致返回的view为viewGroup 196 | View imageLayout = inflate(getContext(), R.layout.item_album_pager, null); 197 | viewGroup.addView(imageLayout); 198 | assert imageLayout != null; 199 | MatrixImageView imageView = (MatrixImageView) imageLayout.findViewById(R.id.image); 200 | imageView.setOnMovingListener(AlbumViewPager.this); 201 | imageView.setOnSingleTapListener(onSingleTapListener); 202 | LocalImageHelper.LocalFile path=paths.get(position); 203 | ImageLoader.getInstance().displayImage(path.getOriginalUri(), new ImageViewAware(imageView), localOptions, loadingListenerr, 204 | new ProcressListener(imageLayout),path.getOrientation()); 205 | 206 | return imageLayout; 207 | } 208 | 209 | 210 | 211 | @Override 212 | public int getItemPosition(Object object) { 213 | //在notifyDataSetChanged时返回None,重新绘制 214 | return POSITION_NONE; 215 | } 216 | 217 | @Override 218 | public void destroyItem(ViewGroup container, int arg1, Object object) { 219 | ((ViewPager) container).removeView((View) object); 220 | } 221 | 222 | @Override 223 | public boolean isViewFromObject(View arg0, Object arg1) { 224 | return arg0 == arg1; 225 | } 226 | } 227 | 228 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/common/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.common; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.InputStreamReader; 8 | import java.security.MessageDigest; 9 | import java.text.ParseException; 10 | import java.text.SimpleDateFormat; 11 | import java.util.Calendar; 12 | import java.util.Date; 13 | import java.util.TimeZone; 14 | import java.util.regex.Pattern; 15 | import java.util.zip.GZIPInputStream; 16 | 17 | /** 18 | * 字符串操作工具包 19 | * 20 | * @author liux (http://my.oschina.net/liux) 21 | * @version 1.0 22 | * @created 2012-3-21 23 | */ 24 | public class StringUtils { 25 | private final static Pattern emailer = Pattern 26 | .compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"); 27 | // private final static SimpleDateFormat dateFormater = new 28 | // SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 29 | // private final static SimpleDateFormat dateFormater2 = new 30 | // SimpleDateFormat("yyyy-MM-dd"); 31 | 32 | private final static ThreadLocal dateFormater = new ThreadLocal() { 33 | @Override 34 | protected SimpleDateFormat initialValue() { 35 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 36 | } 37 | }; 38 | 39 | private final static ThreadLocal dateFormater2 = new ThreadLocal() { 40 | @Override 41 | protected SimpleDateFormat initialValue() { 42 | return new SimpleDateFormat("yyyy-MM-dd"); 43 | } 44 | }; 45 | 46 | /** 47 | * 将字符串转为日期类型 48 | * 49 | * @param sdate 50 | * @return 51 | */ 52 | public static Date toDate(String sdate) { 53 | try { 54 | return dateFormater.get().parse(sdate); 55 | } catch (ParseException e) { 56 | return null; 57 | } 58 | } 59 | 60 | 61 | /** 62 | * 判断给定字符串时间是否为今日 63 | * 64 | * @param sdate 65 | * @return boolean 66 | */ 67 | public static boolean isToday(String sdate) { 68 | boolean b = false; 69 | Date time = toDate(sdate); 70 | Date today = new Date(); 71 | if (time != null) { 72 | String nowDate = dateFormater2.get().format(today); 73 | String timeDate = dateFormater2.get().format(time); 74 | if (nowDate.equals(timeDate)) { 75 | b = true; 76 | } 77 | } 78 | return b; 79 | } 80 | 81 | /** 82 | * 返回long类型的今天的日期 83 | * 84 | * @return 85 | */ 86 | public static long getToday() { 87 | Calendar cal = Calendar.getInstance(); 88 | String curDate = dateFormater2.get().format(cal.getTime()); 89 | curDate = curDate.replace("-", ""); 90 | return Long.parseLong(curDate); 91 | } 92 | 93 | /** 94 | * @Description: 返回字符串格式的当前时间 95 | *@return 96 | */ 97 | public static String getCurrentTime(){ 98 | return dateFormater.get().format(new Date()); 99 | } 100 | /** 101 | * 判断给定字符串是否空白串。 空白串是指由空格、制表符、回车符、换行符组成的字符串 若输入字符串为null或空字符串,返回true 102 | * 103 | * @param input 104 | * @return boolean 105 | */ 106 | public static boolean isEmpty(String input) { 107 | if (input == null || "".equals(input)) 108 | return true; 109 | 110 | for (int i = 0; i < input.length(); i++) { 111 | char c = input.charAt(i); 112 | if (c != ' ' && c != '\t' && c != '\r' && c != '\n') { 113 | return false; 114 | } 115 | } 116 | return true; 117 | } 118 | 119 | 120 | /** 121 | * 字符串转整数 122 | * 123 | * @param str 124 | * @param defValue 125 | * @return 126 | */ 127 | public static int toInt(String str, int defValue) { 128 | try { 129 | return Integer.parseInt(str); 130 | } catch (Exception e) { 131 | } 132 | return defValue; 133 | } 134 | 135 | /** 136 | * 对象转整数 137 | * 138 | * @param obj 139 | * @return 转换异常返回 0 140 | */ 141 | public static int toInt(Object obj) { 142 | if (obj == null) 143 | return 0; 144 | return toInt(obj.toString(), 0); 145 | } 146 | 147 | /** 148 | * 对象转整数 149 | * 150 | * @param obj 151 | * @return 转换异常返回 0 152 | */ 153 | public static long toLong(String obj) { 154 | try { 155 | return Long.parseLong(obj); 156 | } catch (Exception e) { 157 | } 158 | return 0; 159 | } 160 | 161 | 162 | /** 163 | * 对象转浮点 164 | * 165 | * @param obj 166 | * @return 转换异常返回 0 167 | */ 168 | public static double toDouble(String obj) { 169 | try { 170 | return Double.parseDouble(obj); 171 | } catch (Exception e) { 172 | } 173 | return 0; 174 | } 175 | /** 176 | * 字符串转布尔值 177 | * 178 | * @param b 179 | * @return 转换异常返回 false 180 | */ 181 | public static boolean toBool(String b) { 182 | try { 183 | return Boolean.parseBoolean(b); 184 | } catch (Exception e) { 185 | } 186 | return false; 187 | } 188 | 189 | /** 190 | * 将一个InputStream流转换成字符串 191 | * 192 | * @param is 193 | * @return 194 | */ 195 | public static String toConvertString(InputStream is) { 196 | StringBuffer res = new StringBuffer(); 197 | InputStreamReader isr = new InputStreamReader(is); 198 | BufferedReader read = new BufferedReader(isr); 199 | try { 200 | String line; 201 | line = read.readLine(); 202 | while (line != null) { 203 | res.append(line); 204 | line = read.readLine(); 205 | } 206 | } catch (IOException e) { 207 | e.printStackTrace(); 208 | } finally { 209 | try { 210 | if (null != isr) { 211 | isr.close(); 212 | isr.close(); 213 | } 214 | if (null != read) { 215 | read.close(); 216 | read = null; 217 | } 218 | if (null != is) { 219 | is.close(); 220 | is = null; 221 | } 222 | } catch (IOException e) { 223 | } 224 | } 225 | return res.toString(); 226 | } 227 | // 解压缩 228 | public static String uncompress(InputStream str) throws IOException { 229 | if (str == null ) { 230 | return ""; 231 | } 232 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 233 | 234 | GZIPInputStream gunzip = new GZIPInputStream(str); 235 | byte[] buffer = new byte[256]; 236 | int n; 237 | while ((n = gunzip.read(buffer))>= 0) { 238 | out.write(buffer, 0, n); 239 | } 240 | // toString()使用平台默认编码,也可以显式的指定如toString("GBK") 241 | return out.toString("utf-8"); 242 | } 243 | //M5D加密 244 | public static String MD5(String s) { 245 | char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 246 | try { 247 | byte[] btInput = s.getBytes(); 248 | // 获得MD5摘要算法的 MessageDigest 对象 249 | MessageDigest mdInst = MessageDigest.getInstance("MD5"); 250 | // 使用指定的字节更新摘要 251 | mdInst.update(btInput); 252 | // 获得密文 253 | byte[] md = mdInst.digest(); 254 | // 把密文转换成十六进制的字符串形式 255 | int j = md.length; 256 | char str[] = new char[j * 2]; 257 | int k = 0; 258 | for (int i = 0; i < j; i++) { 259 | byte byte0 = md[i]; 260 | str[k++] = hexDigits[byte0 >>> 4 & 0xf]; 261 | str[k++] = hexDigits[byte0 & 0xf]; 262 | } 263 | return new String(str); 264 | } catch (Exception e) { 265 | e.printStackTrace(); 266 | return null; 267 | } 268 | } 269 | 270 | private static final double EARTH_RADIUS = 6378137.0; 271 | public static double gps2m(double lat_a, double lng_a, double lat_b, double lng_b) { 272 | double radLat1 = (lat_a * Math.PI / 180.0); 273 | double radLat2 = (lat_b * Math.PI / 180.0); 274 | double a = radLat1 - radLat2; 275 | double b = (lng_a - lng_b) * Math.PI / 180.0; 276 | double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) 277 | + Math.cos(radLat1) * Math.cos(radLat2) 278 | * Math.pow(Math.sin(b / 2), 2))); 279 | s = s * EARTH_RADIUS; 280 | s = Math.round(s * 10000) / 10000; 281 | return s; 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/common/LocalImageHelper.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.common; 2 | 3 | import android.database.Cursor; 4 | import android.provider.MediaStore; 5 | 6 | 7 | import com.example.localalbum.AppContext; 8 | 9 | import java.io.File; 10 | import java.text.SimpleDateFormat; 11 | import java.util.ArrayList; 12 | import java.util.Date; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | /** 18 | * Created by linjizong on 15/6/11. 19 | */ 20 | public class LocalImageHelper { 21 | private static LocalImageHelper instance; 22 | private final AppContext context; 23 | final List checkedItems = new ArrayList<>(); 24 | 25 | public int getCurrentSize() { 26 | return currentSize; 27 | } 28 | 29 | public void setCurrentSize(int currentSize) { 30 | this.currentSize = currentSize; 31 | } 32 | 33 | //当前选中得图片个数 34 | private int currentSize; 35 | public String getCameraImgPath() { 36 | return CameraImgPath; 37 | } 38 | 39 | public String setCameraImgPath() { 40 | String foloder= AppContext.getInstance().getCachePath() 41 | + "/PostPicture/"; 42 | File savedir = new File(foloder); 43 | if (!savedir.exists()) { 44 | savedir.mkdirs(); 45 | } 46 | String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss") 47 | .format(new Date()); 48 | // 照片命名 49 | String picName = timeStamp + ".jpg"; 50 | // 裁剪头像的绝对路径 51 | CameraImgPath = foloder + picName; 52 | return CameraImgPath; 53 | } 54 | 55 | //拍照时指定保存图片的路径 56 | private String CameraImgPath; 57 | //大图遍历字段 58 | private static final String[] STORE_IMAGES = { 59 | MediaStore.Images.Media._ID, 60 | MediaStore.Images.Media.DATA, 61 | MediaStore.Images.Media.ORIENTATION 62 | }; 63 | //小图遍历字段 64 | private static final String[] THUMBNAIL_STORE_IMAGE = { 65 | MediaStore.Images.Thumbnails._ID, 66 | MediaStore.Images.Thumbnails.DATA 67 | }; 68 | 69 | final List paths = new ArrayList<>(); 70 | 71 | final Map> folders = new HashMap<>(); 72 | 73 | private LocalImageHelper(AppContext context) { 74 | this.context = context; 75 | } 76 | 77 | public Map> getFolderMap() { 78 | return folders; 79 | } 80 | 81 | public static LocalImageHelper getInstance() { 82 | return instance; 83 | } 84 | 85 | public static void init(AppContext context) { 86 | instance = new LocalImageHelper(context); 87 | new Thread(new Runnable() { 88 | @Override 89 | public void run() { 90 | instance.initImage(); 91 | } 92 | }).start(); 93 | } 94 | 95 | public boolean isInited() { 96 | return paths.size() > 0; 97 | } 98 | 99 | public List getCheckedItems() { 100 | return checkedItems; 101 | } 102 | 103 | private boolean resultOk; 104 | 105 | public boolean isResultOk() { 106 | return resultOk; 107 | } 108 | 109 | public void setResultOk(boolean ok) { 110 | resultOk = ok; 111 | } 112 | 113 | private boolean isRunning = false; 114 | 115 | public synchronized void initImage() { 116 | if (isRunning) 117 | return; 118 | isRunning=true; 119 | if (isInited()) 120 | return; 121 | //获取大图的游标 122 | Cursor cursor = context.getContentResolver().query( 123 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, // 大图URI 124 | STORE_IMAGES, // 字段 125 | null, // No where clause 126 | null, // No where clause 127 | MediaStore.Images.Media.DATE_TAKEN + " DESC"); //根据时间升序 128 | if (cursor == null) 129 | return; 130 | while (cursor.moveToNext()) { 131 | int id = cursor.getInt(0);//大图ID 132 | String path = cursor.getString(1);//大图路径 133 | File file = new File(path); 134 | //判断大图是否存在 135 | if (file.exists()) { 136 | //小图URI 137 | String thumbUri = getThumbnail(id, path); 138 | //获取大图URI 139 | String uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon(). 140 | appendPath(Integer.toString(id)).build().toString(); 141 | if(StringUtils.isEmpty(uri)) 142 | continue; 143 | if (StringUtils.isEmpty(thumbUri)) 144 | thumbUri = uri; 145 | //获取目录名 146 | String folder = file.getParentFile().getName(); 147 | 148 | LocalFile localFile = new LocalFile(); 149 | localFile.setOriginalUri(uri); 150 | localFile.setThumbnailUri(thumbUri); 151 | int degree = cursor.getInt(2); 152 | if (degree != 0) { 153 | degree = degree + 180; 154 | } 155 | localFile.setOrientation(360-degree); 156 | 157 | paths.add(localFile); 158 | //判断文件夹是否已经存在 159 | if (folders.containsKey(folder)) { 160 | folders.get(folder).add(localFile); 161 | } else { 162 | List files = new ArrayList<>(); 163 | files.add(localFile); 164 | folders.put(folder, files); 165 | } 166 | } 167 | } 168 | folders.put("所有图片", paths); 169 | cursor.close(); 170 | isRunning=false; 171 | } 172 | 173 | private String getThumbnail(int id, String path) { 174 | //获取大图的缩略图 175 | Cursor cursor = context.getContentResolver().query(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, 176 | THUMBNAIL_STORE_IMAGE, 177 | MediaStore.Images.Thumbnails.IMAGE_ID + " = ?", 178 | new String[]{id + ""}, 179 | null); 180 | if (cursor.getCount() > 0) { 181 | cursor.moveToFirst(); 182 | int thumId = cursor.getInt(0); 183 | String uri = MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI.buildUpon(). 184 | appendPath(Integer.toString(thumId)).build().toString(); 185 | cursor.close(); 186 | return uri; 187 | } 188 | cursor.close(); 189 | return null; 190 | } 191 | 192 | public List getFolder(String folder) { 193 | return folders.get(folder); 194 | } 195 | 196 | public void clear(){ 197 | checkedItems.clear(); 198 | currentSize=(0); 199 | String foloder= AppContext.getInstance().getCachePath() 200 | + "/PostPicture/"; 201 | File savedir = new File(foloder); 202 | if (savedir.exists()) { 203 | deleteFile(savedir); 204 | } 205 | } 206 | public void deleteFile(File file) { 207 | 208 | if (file.exists()) { 209 | if (file.isFile()) { 210 | file.delete(); 211 | } else if (file.isDirectory()) { 212 | File files[] = file.listFiles(); 213 | for (int i = 0; i < files.length; i++) { 214 | deleteFile(files[i]); 215 | } 216 | } 217 | } else { 218 | } 219 | } 220 | public static class LocalFile { 221 | private String originalUri;//原图URI 222 | private String thumbnailUri;//缩略图URI 223 | private int orientation;//图片旋转角度 224 | 225 | public String getThumbnailUri() { 226 | return thumbnailUri; 227 | } 228 | 229 | public void setThumbnailUri(String thumbnailUri) { 230 | this.thumbnailUri = thumbnailUri; 231 | } 232 | 233 | public String getOriginalUri() { 234 | return originalUri; 235 | } 236 | 237 | public void setOriginalUri(String originalUri) { 238 | this.originalUri = originalUri; 239 | } 240 | 241 | 242 | public int getOrientation() { 243 | return orientation; 244 | } 245 | 246 | public void setOrientation(int exifOrientation) { 247 | orientation = exifOrientation; 248 | } 249 | 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/ui/LocalAlbum.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.ui; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.res.Configuration; 6 | import android.graphics.Bitmap; 7 | import android.media.ExifInterface; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.os.Handler; 11 | import android.provider.MediaStore; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.animation.Animation; 16 | import android.view.animation.AnimationUtils; 17 | import android.widget.AdapterView; 18 | import android.widget.BaseAdapter; 19 | import android.widget.ImageView; 20 | import android.widget.ListView; 21 | import android.widget.TextView; 22 | import android.widget.Toast; 23 | 24 | 25 | import com.example.localalbum.AppContext; 26 | import com.example.localalbum.R; 27 | import com.example.localalbum.common.ExtraKey; 28 | import com.example.localalbum.common.ImageUtils; 29 | import com.example.localalbum.common.LocalImageHelper; 30 | import com.example.localalbum.common.StringUtils; 31 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 32 | import com.nostra13.universalimageloader.core.ImageLoader; 33 | import com.nostra13.universalimageloader.core.assist.ImageSize; 34 | import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; 35 | import com.nostra13.universalimageloader.core.imageaware.ImageViewAware; 36 | 37 | import java.io.File; 38 | import java.io.IOException; 39 | import java.util.ArrayList; 40 | import java.util.Collections; 41 | import java.util.Comparator; 42 | import java.util.Iterator; 43 | import java.util.List; 44 | import java.util.Map; 45 | 46 | /** 47 | * Created by linjizong on 15/6/12. 48 | * 本地相册 49 | */ 50 | public class LocalAlbum extends BaseActivity { 51 | ListView listView; 52 | ImageView progress; 53 | LocalImageHelper helper; 54 | View camera; 55 | List folderNames; 56 | 57 | @Override 58 | protected void onCreate(Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | setContentView(R.layout.local_album); 61 | listView = (ListView) findViewById(R.id.local_album_list); 62 | camera = findViewById(R.id.loacal_album_camera); 63 | camera.setOnClickListener(onClickListener); 64 | camera.setVisibility(View.GONE); 65 | progress = (ImageView) findViewById(R.id.progress_bar); 66 | helper = LocalImageHelper.getInstance(); 67 | Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate_loading); 68 | progress.startAnimation(animation); 69 | findViewById(R.id.album_back).setOnClickListener(new View.OnClickListener() { 70 | @Override 71 | public void onClick(View view) { 72 | finish(); 73 | } 74 | }); 75 | new Thread(new Runnable() { 76 | @Override 77 | public void run() { 78 | //开启线程初始化本地图片列表,该方法是synchronized的,因此当AppContent在初始化时,此处阻塞 79 | LocalImageHelper.getInstance().initImage(); 80 | runOnUiThread(new Runnable() { 81 | @Override 82 | public void run() { 83 | //初始化完毕后,显示文件夹列表 84 | if (!isDestroy) { 85 | initAdapter(); 86 | progress.clearAnimation(); 87 | ((View) progress.getParent()).setVisibility(View.GONE); 88 | listView.setVisibility(View.VISIBLE); 89 | camera.setVisibility(View.VISIBLE); 90 | } 91 | } 92 | }); 93 | } 94 | }).start(); 95 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 96 | @Override 97 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 98 | Intent intent = new Intent(LocalAlbum.this, LocalAlbumDetail.class); 99 | intent.putExtra(ExtraKey.LOCAL_FOLDER_NAME, folderNames.get(i)); 100 | intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 101 | startActivity(intent); 102 | } 103 | }); 104 | } 105 | 106 | public void initAdapter() { 107 | listView.setAdapter(new FolderAdapter(this, helper.getFolderMap())); 108 | } 109 | 110 | View.OnClickListener onClickListener = new View.OnClickListener() { 111 | @Override 112 | public void onClick(View view) { 113 | if(LocalImageHelper.getInstance().getCurrentSize()+LocalImageHelper.getInstance().getCheckedItems().size()>=9){ 114 | Toast.makeText(LocalAlbum.this,"最多选择9张图片",Toast.LENGTH_SHORT).show(); 115 | return; 116 | } 117 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 118 | // 拍照后保存图片的绝对路径 119 | String cameraPath = LocalImageHelper.getInstance().setCameraImgPath(); 120 | File file = new File(cameraPath); 121 | intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); 122 | startActivityForResult(intent, 123 | ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA); 124 | } 125 | }; 126 | 127 | @Override 128 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 129 | if (resultCode == RESULT_OK) { 130 | switch (requestCode) { 131 | case ImageUtils.REQUEST_CODE_GETIMAGE_BYCAMERA: 132 | String cameraPath = LocalImageHelper.getInstance().getCameraImgPath(); 133 | if (StringUtils.isEmpty(cameraPath)) { 134 | Toast.makeText(this, "图片获取失败", Toast.LENGTH_SHORT).show(); 135 | return; 136 | } 137 | File file = new File(cameraPath); 138 | if (file.exists()) { 139 | Uri uri = Uri.fromFile(file); 140 | LocalImageHelper.LocalFile localFile = new LocalImageHelper.LocalFile(); 141 | localFile.setThumbnailUri(uri.toString()); 142 | localFile.setOriginalUri(uri.toString()); 143 | localFile.setOrientation(getBitmapDegree(cameraPath)); 144 | LocalImageHelper.getInstance().getCheckedItems().add(localFile); 145 | LocalImageHelper.getInstance().setResultOk(true); 146 | new Thread(new Runnable() { 147 | @Override 148 | public void run() { 149 | 150 | } 151 | }); 152 | //这里本来有个弹出progressDialog的,在拍照结束后关闭,但是要延迟1秒,原因是由于三星手机的相机会强制切换到横屏, 153 | //此处必须等它切回竖屏了才能结束,否则会有异常 154 | new Handler().postDelayed(new Runnable() { 155 | @Override 156 | public void run() { 157 | finish(); 158 | } 159 | },1000); 160 | } else { 161 | Toast.makeText(this, "图片获取失败", Toast.LENGTH_SHORT).show(); 162 | } 163 | break; 164 | default: 165 | break; 166 | } 167 | } 168 | } 169 | 170 | /** 171 | * 读取图片的旋转的角度,还是三星的问题,需要根据图片的旋转角度正确显示 172 | * 173 | * @param path 图片绝对路径 174 | * @return 图片的旋转角度 175 | */ 176 | private int getBitmapDegree(String path) { 177 | int degree = 0; 178 | try { 179 | // 从指定路径下读取图片,并获取其EXIF信息 180 | ExifInterface exifInterface = new ExifInterface(path); 181 | // 获取图片的旋转信息 182 | int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 183 | ExifInterface.ORIENTATION_NORMAL); 184 | switch (orientation) { 185 | case ExifInterface.ORIENTATION_ROTATE_90: 186 | degree = 90; 187 | break; 188 | case ExifInterface.ORIENTATION_ROTATE_180: 189 | degree = 180; 190 | break; 191 | case ExifInterface.ORIENTATION_ROTATE_270: 192 | degree = 270; 193 | break; 194 | } 195 | } catch (IOException e) { 196 | e.printStackTrace(); 197 | } 198 | return degree; 199 | } 200 | 201 | @Override 202 | public void onConfigurationChanged(Configuration newConfig) { 203 | super.onConfigurationChanged(newConfig); 204 | } 205 | 206 | public class FolderAdapter extends BaseAdapter { 207 | Map> folders; 208 | Context context; 209 | DisplayImageOptions options; 210 | 211 | FolderAdapter(Context context, Map> folders) { 212 | this.folders = folders; 213 | this.context = context; 214 | folderNames = new ArrayList<>(); 215 | 216 | options = new DisplayImageOptions.Builder() 217 | .cacheInMemory(true) 218 | .cacheOnDisk(false) 219 | .showImageForEmptyUri(R.drawable.dangkr_no_picture_small) 220 | .showImageOnFail(R.drawable.dangkr_no_picture_small) 221 | .showImageOnLoading(R.drawable.dangkr_no_picture_small) 222 | .bitmapConfig(Bitmap.Config.RGB_565) 223 | .setImageSize(new ImageSize(((AppContext) context.getApplicationContext()).getQuarterWidth(), 0)) 224 | .displayer(new SimpleBitmapDisplayer()).build(); 225 | 226 | Iterator iter = folders.entrySet().iterator(); 227 | while (iter.hasNext()) { 228 | Map.Entry entry = (Map.Entry) iter.next(); 229 | String key = (String) entry.getKey(); 230 | folderNames.add(key); 231 | } 232 | //根据文件夹内的图片数量降序显示 233 | Collections.sort(folderNames, new Comparator() { 234 | public int compare(String arg0, String arg1) { 235 | Integer num1 = helper.getFolder(arg0).size(); 236 | Integer num2 = helper.getFolder(arg1).size(); 237 | return num2.compareTo(num1); 238 | } 239 | }); 240 | } 241 | 242 | @Override 243 | public int getCount() { 244 | return folders.size(); 245 | } 246 | 247 | @Override 248 | public Object getItem(int i) { 249 | return null; 250 | } 251 | 252 | @Override 253 | public long getItemId(int i) { 254 | return 0; 255 | } 256 | 257 | @Override 258 | public View getView(int i, View convertView, ViewGroup viewGroup) { 259 | ViewHolder viewHolder; 260 | if (convertView == null || convertView.getTag() == null) { 261 | viewHolder = new ViewHolder(); 262 | convertView = LayoutInflater.from(context).inflate(R.layout.item_albumfoler, null); 263 | viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView); 264 | viewHolder.textView = (TextView) convertView.findViewById(R.id.textview); 265 | convertView.setTag(viewHolder); 266 | } else { 267 | viewHolder = (ViewHolder) convertView.getTag(); 268 | } 269 | String name = folderNames.get(i); 270 | List files = folders.get(name); 271 | viewHolder.textView.setText(name + "(" + files.size() + ")"); 272 | if (files.size() > 0) { 273 | ImageLoader.getInstance().displayImage(files.get(0).getThumbnailUri(), new ImageViewAware(viewHolder.imageView), options, 274 | null, null, files.get(0).getOrientation()); 275 | } 276 | return convertView; 277 | } 278 | 279 | private class ViewHolder { 280 | ImageView imageView; 281 | TextView textView; 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/widget/MatrixImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Color; 6 | import android.graphics.Matrix; 7 | import android.graphics.PointF; 8 | import android.util.AttributeSet; 9 | import android.view.GestureDetector; 10 | import android.view.GestureDetector.SimpleOnGestureListener; 11 | import android.view.MotionEvent; 12 | import android.view.View; 13 | import android.view.ViewTreeObserver; 14 | import android.widget.ImageView; 15 | 16 | /** 17 | * @ClassName: MatrixImageView 18 | * @Description: 带放大、缩小、移动效果的ImageView 19 | * @author LinJ 20 | * @date 2015-1-7 上午11:15:07 21 | * 22 | */ 23 | public class MatrixImageView extends ImageView{ 24 | public final static String TAG="MatrixImageView"; 25 | private GestureDetector mGestureDetector; 26 | /** 模板Matrix,用以初始化 */ 27 | private Matrix mMatrix=new Matrix(); 28 | /** 图片长度*/ 29 | private float mImageWidth; 30 | /** 图片高度 */ 31 | private float mImageHeight; 32 | /** 原始缩放级别 */ 33 | private float mScale 34 | ; 35 | private OnMovingListener moveListener; 36 | private OnSingleTapListener singleTapListener; 37 | 38 | public MatrixImageView(Context context, AttributeSet attrs) { 39 | super(context, attrs); 40 | MatrixTouchListener mListener=new MatrixTouchListener(); 41 | setOnTouchListener(mListener); 42 | mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener)); 43 | //背景设置为balck 44 | setBackgroundColor(Color.BLACK); 45 | //将缩放类型设置为CENTER_INSIDE,表示把图片居中显示,并且宽高最大值为控件宽高 46 | setScaleType(ScaleType.FIT_CENTER); 47 | } 48 | public MatrixImageView(Context context) { 49 | super(context, null); 50 | MatrixTouchListener mListener=new MatrixTouchListener(); 51 | setOnTouchListener(mListener); 52 | mGestureDetector=new GestureDetector(getContext(), new GestureListener(mListener)); 53 | //背景设置为balck 54 | setBackgroundColor(Color.BLACK); 55 | //将缩放类型设置为CENTER_INSIDE,表示把图片居中显示,并且宽高最大值为控件宽高 56 | setScaleType(ScaleType.FIT_CENTER); 57 | } 58 | public void setOnMovingListener(OnMovingListener listener){ 59 | moveListener=listener; 60 | } 61 | public void setOnSingleTapListener(OnSingleTapListener onSingleTapListener) { 62 | this.singleTapListener = onSingleTapListener; 63 | } 64 | @Override 65 | public void setImageBitmap(Bitmap bm) { 66 | // TODO Auto-generated method stub 67 | super.setImageBitmap(bm); 68 | //大小为0 表示当前控件大小未测量 设置监听函数 在绘制前赋值 69 | if(getWidth()==0){ 70 | ViewTreeObserver vto = getViewTreeObserver(); 71 | vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() 72 | { 73 | public boolean onPreDraw() 74 | { 75 | initData(); 76 | //赋值结束后,移除该监听函数 77 | MatrixImageView.this.getViewTreeObserver().removeOnPreDrawListener(this); 78 | return true; 79 | } 80 | }); 81 | }else { 82 | initData(); 83 | } 84 | } 85 | 86 | /** 87 | * 初始化模板Matrix和图片的其他数据 88 | */ 89 | private void initData() { 90 | //设置完图片后,获取该图片的坐标变换矩阵 91 | mMatrix.set(getImageMatrix()); 92 | float[] values=new float[9]; 93 | mMatrix.getValues(values); 94 | //图片宽度为屏幕宽度除缩放倍数 95 | mImageWidth=getWidth()/values[Matrix.MSCALE_X]; 96 | mImageHeight=(getHeight()-values[Matrix.MTRANS_Y]*2)/values[Matrix.MSCALE_Y]; 97 | mScale=values[Matrix.MSCALE_X]; 98 | } 99 | 100 | public class MatrixTouchListener implements OnTouchListener{ 101 | /** 拖拉照片模式 */ 102 | private static final int MODE_DRAG = 1; 103 | /** 放大缩小照片模式 */ 104 | private static final int MODE_ZOOM = 2; 105 | /** 不支持Matrix */ 106 | private static final int MODE_UNABLE=3; 107 | /** 最大缩放级别*/ 108 | float mMaxScale=6; 109 | /** 双击时的缩放级别*/ 110 | float mDobleClickScale=2; 111 | private int mMode = 0;// 112 | /** 缩放开始时的手指间距 */ 113 | private float mStartDis; 114 | /** 当前Matrix*/ 115 | private Matrix mCurrentMatrix = new Matrix(); 116 | 117 | /** 用于记录开始时候的坐标位置 */ 118 | 119 | /** 和ViewPager交互相关,判断当前是否可以左移、右移 */ 120 | boolean mLeftDragable; 121 | boolean mRightDragable; 122 | /** 是否第一次移动 */ 123 | boolean mFirstMove=false; 124 | private PointF mStartPoint = new PointF(); 125 | @Override 126 | public boolean onTouch(View v, MotionEvent event) { 127 | // TODO Auto-generated method stub 128 | switch (event.getActionMasked()) { 129 | case MotionEvent.ACTION_DOWN: 130 | //设置拖动模式 131 | mMode=MODE_DRAG; 132 | mStartPoint.set(event.getX(), event.getY()); 133 | isMatrixEnable(); 134 | startDrag(); 135 | checkDragable(); 136 | break; 137 | case MotionEvent.ACTION_UP: 138 | case MotionEvent.ACTION_CANCEL: 139 | reSetMatrix(); 140 | stopDrag(); 141 | break; 142 | case MotionEvent.ACTION_MOVE: 143 | if (mMode == MODE_ZOOM) { 144 | setZoomMatrix(event); 145 | }else if (mMode==MODE_DRAG) { 146 | setDragMatrix(event); 147 | }else { 148 | stopDrag(); 149 | } 150 | break; 151 | case MotionEvent.ACTION_POINTER_DOWN: 152 | if(mMode==MODE_UNABLE) return true; 153 | mMode=MODE_ZOOM; 154 | mStartDis = distance(event); 155 | break; 156 | case MotionEvent.ACTION_POINTER_UP: 157 | 158 | break; 159 | default: 160 | break; 161 | } 162 | return mGestureDetector.onTouchEvent(event); 163 | } 164 | 165 | /** 166 | * 子控件开始进入移动状态,令ViewPager无法拦截对子控件的Touch事件 167 | */ 168 | private void startDrag(){ 169 | if(moveListener!=null) moveListener.startDrag(); 170 | 171 | } 172 | /** 173 | * 子控件开始停止移动状态,ViewPager将拦截对子控件的Touch事件 174 | */ 175 | private void stopDrag(){ 176 | if(moveListener!=null) moveListener.stopDrag(); 177 | } 178 | 179 | /** 180 | * 根据当前图片左右边缘设置可拖拽状态 181 | */ 182 | private void checkDragable() { 183 | mLeftDragable=true; 184 | mRightDragable=true; 185 | mFirstMove=true; 186 | float[] values=new float[9]; 187 | getImageMatrix().getValues(values); 188 | //图片左边缘离开左边界,表示不可右移 189 | if(values[Matrix.MTRANS_X]>=0) 190 | mRightDragable=false; 191 | //图片右边缘离开右边界,表示不可左移 192 | if((mImageWidth)*values[Matrix.MSCALE_X]+values[Matrix.MTRANS_X]<=getWidth()){ 193 | mLeftDragable=false; 194 | } 195 | } 196 | 197 | /** 198 | * 设置拖拽状态下的Matrix 199 | * @param event 200 | */ 201 | public void setDragMatrix(MotionEvent event) { 202 | if(isZoomChanged()){ 203 | float dx = event.getX() - mStartPoint.x; // 得到x轴的移动距离 204 | float dy = event.getY() - mStartPoint.y; // 得到x轴的移动距离 205 | //避免和双击冲突,大于10f才算是拖动 206 | if(Math.sqrt(dx*dx+dy*dy)>10f){ 207 | mStartPoint.set(event.getX(), event.getY()); 208 | //在当前基础上移动 209 | mCurrentMatrix.set(getImageMatrix()); 210 | float[] values=new float[9]; 211 | mCurrentMatrix.getValues(values); 212 | dy=checkDyBound(values,dy); 213 | dx=checkDxBound(values,dx,dy); 214 | 215 | mCurrentMatrix.postTranslate(dx, dy); 216 | setImageMatrix(mCurrentMatrix); 217 | } 218 | }else { 219 | stopDrag(); 220 | } 221 | } 222 | 223 | /** 224 | * 判断缩放级别是否是改变过 225 | * @return true表示非初始值,false表示初始值 226 | */ 227 | private boolean isZoomChanged() { 228 | float[] values=new float[9]; 229 | getImageMatrix().getValues(values); 230 | //获取当前X轴缩放级别 231 | float scale=values[Matrix.MSCALE_X]; 232 | //获取模板的X轴缩放级别,两者做比较 233 | return scale!=mScale; 234 | } 235 | 236 | /** 237 | * 和当前矩阵对比,检验dy,使图像移动后不会超出ImageView边界 238 | * @param values 239 | * @param dy 240 | * @return 241 | */ 242 | private float checkDyBound(float[] values, float dy) { 243 | float height=getHeight(); 244 | if(mImageHeight*values[Matrix.MSCALE_Y]0) 247 | dy=-values[Matrix.MTRANS_Y]; 248 | else if(values[Matrix.MTRANS_Y]+dy<-(mImageHeight*values[Matrix.MSCALE_Y]-height)) 249 | dy=-(mImageHeight*values[Matrix.MSCALE_Y]-height)-values[Matrix.MTRANS_Y]; 250 | return dy; 251 | } 252 | 253 | /** 254 | * 和当前矩阵对比,检验dx,使图像移动后不会超出ImageView边界 255 | * @param values 256 | * @param dx 257 | * @return 258 | */ 259 | private float checkDxBound(float[] values,float dx,float dy) { 260 | float width=getWidth(); 261 | if(!mLeftDragable&&dx<0){ 262 | //加入和y轴的对比,表示在监听到垂直方向的手势时不切换Item 263 | if(Math.abs(dx)*0.4f>Math.abs(dy)&&mFirstMove){ 264 | stopDrag(); 265 | } 266 | return 0; 267 | } 268 | if(!mRightDragable&&dx>0){ 269 | //加入和y轴的对比,表示在监听到垂直方向的手势时不切换Item 270 | if(Math.abs(dx)*0.4f>Math.abs(dy)&&mFirstMove){ 271 | stopDrag(); 272 | } 273 | return 0; 274 | } 275 | mLeftDragable=true; 276 | mRightDragable=true; 277 | if(mFirstMove) mFirstMove=false; 278 | if(mImageWidth*values[Matrix.MSCALE_X]0){ 283 | dx=-values[Matrix.MTRANS_X]; 284 | } 285 | else if(values[Matrix.MTRANS_X]+dx<-(mImageWidth*values[Matrix.MSCALE_X]-width)){ 286 | dx=-(mImageWidth*values[Matrix.MSCALE_X]-width)-values[Matrix.MTRANS_X]; 287 | } 288 | return dx; 289 | } 290 | 291 | /** 292 | * 设置缩放Matrix 293 | * @param event 294 | */ 295 | private void setZoomMatrix(MotionEvent event) { 296 | //只有同时触屏两个点的时候才执行 297 | if(event.getPointerCount()<2) return; 298 | float endDis = distance(event);// 结束距离 299 | if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10 300 | float scale = endDis / mStartDis;// 得到缩放倍数 301 | mStartDis=endDis;//重置距离 302 | mCurrentMatrix.set(getImageMatrix());//初始化Matrix 303 | float[] values=new float[9]; 304 | mCurrentMatrix.getValues(values); 305 | scale = checkMaxScale(scale, values); 306 | PointF centerF=getCenter(scale,values); 307 | mCurrentMatrix.postScale(scale, scale,centerF.x,centerF.y); 308 | setImageMatrix(mCurrentMatrix); 309 | } 310 | } 311 | 312 | /** 313 | * 获取缩放的中心点。 314 | * @param scale 315 | * @param values 316 | * @return 317 | */ 318 | private PointF getCenter(float scale,float[] values) { 319 | //缩放级别小于原始缩放级别时或者为放大状态时,返回ImageView中心点作为缩放中心点 320 | if(scale*values[Matrix.MSCALE_X]=1){ 321 | return new PointF(getWidth()/2,getHeight()/2); 322 | } 323 | float cx=getWidth()/2; 324 | float cy=getHeight()/2; 325 | //以ImageView中心点为缩放中心,判断缩放后的图片左边缘是否会离开ImageView左边缘,是的话以左边缘为X轴中心 326 | if((getWidth()/2-values[Matrix.MTRANS_X])*scalemMaxScale) 342 | scale=mMaxScale/values[Matrix.MSCALE_X]; 343 | return scale; 344 | } 345 | 346 | /** 347 | * 重置Matrix 348 | */ 349 | private void reSetMatrix() { 350 | if(checkRest()){ 351 | mCurrentMatrix.set(mMatrix); 352 | setImageMatrix(mCurrentMatrix); 353 | }else { 354 | //判断Y轴是否需要更正 355 | float[] values=new float[9]; 356 | getImageMatrix().getValues(values); 357 | float height=mImageHeight*values[Matrix.MSCALE_Y]; 358 | if(height pictures = new ArrayList<>();//图片路径数组 58 | HorizontalScrollView scrollView;//滚动的图片容器 59 | View editContainer;//动态编辑部分 60 | View pagerContainer;//图片显示部分 61 | 62 | //显示大图的viewpager 集成到了Actvity中 下面是和viewpager相关的控件 63 | AlbumViewPager viewpager;//大图显示pager 64 | ImageView mBackView;//返回/关闭大图 65 | TextView mCountView;//大图数量提示 66 | View mHeaderBar;//大图顶部栏 67 | ImageView delete;//删除按钮 68 | 69 | int size;//小图大小 70 | int padding;//小图间距 71 | DisplayImageOptions options; 72 | 73 | @Override 74 | protected void onCreate(Bundle savedInstanceState) { 75 | // TODO Auto-generated method stub 76 | super.onCreate(savedInstanceState); 77 | setContentView(R.layout.post_dynamic); 78 | imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 79 | //设置ImageLoader参数 80 | options = new DisplayImageOptions.Builder() 81 | .cacheInMemory(true) 82 | .cacheOnDisk(false) 83 | .showImageForEmptyUri(R.drawable.dangkr_no_picture_small) 84 | .showImageOnFail(R.drawable.dangkr_no_picture_small) 85 | .showImageOnLoading(R.drawable.dangkr_no_picture_small) 86 | .bitmapConfig(Bitmap.Config.RGB_565) 87 | .displayer(new SimpleBitmapDisplayer()).build(); 88 | initViews(); 89 | initData(); 90 | } 91 | 92 | 93 | /** 94 | * @Description: 初始化Views 95 | */ 96 | private void initViews() { 97 | // TODO Auto-generated method stub 98 | mBack = (ImageView) findViewById(R.id.post_back); 99 | mSend = findViewById(R.id.post_send); 100 | mContent = (EditText) findViewById(R.id.post_content); 101 | textRemain = (TextView) findViewById(R.id.post_text_remain); 102 | picRemain = (TextView) findViewById(R.id.post_pic_remain); 103 | add = (ImageView) findViewById(R.id.post_add_pic); 104 | picContainer = (LinearLayout) findViewById(R.id.post_pic_container); 105 | scrollView = (HorizontalScrollView) findViewById(R.id.post_scrollview); 106 | viewpager = (AlbumViewPager) findViewById(R.id.albumviewpager); 107 | mBackView = (ImageView) findViewById(R.id.header_bar_photo_back); 108 | mCountView = (TextView) findViewById(R.id.header_bar_photo_count); 109 | mHeaderBar = findViewById(R.id.album_item_header_bar); 110 | delete = (ImageView) findViewById(R.id.header_bar_photo_delete); 111 | editContainer = findViewById(R.id.post_edit_container); 112 | pagerContainer = findViewById(R.id.pagerview); 113 | delete.setVisibility(View.VISIBLE); 114 | 115 | viewpager.setOnPageChangeListener(pageChangeListener); 116 | viewpager.setOnSingleTapListener(this); 117 | mBackView.setOnClickListener(this); 118 | mCountView.setOnClickListener(this); 119 | mBack.setOnClickListener(this); 120 | mSend.setOnClickListener(this); 121 | add.setOnClickListener(this); 122 | delete.setOnClickListener(this); 123 | 124 | mContent.addTextChangedListener(new TextWatcher() { 125 | 126 | @Override 127 | public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { 128 | // TODO Auto-generated method stub 129 | 130 | } 131 | 132 | @Override 133 | public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, 134 | int arg3) { 135 | // TODO Auto-generated method stub 136 | 137 | } 138 | 139 | @Override 140 | public void afterTextChanged(Editable content) { 141 | textRemain.setText(content.toString().length() + "/140"); 142 | } 143 | }); 144 | } 145 | 146 | private void initData() { 147 | size = (int) getResources().getDimension(R.dimen.size_100); 148 | padding = (int) getResources().getDimension(R.dimen.padding_10); 149 | } 150 | 151 | @Override 152 | public void onBackPressed() { 153 | if (pagerContainer.getVisibility() != View.VISIBLE) { 154 | //showSaveDialog(); 155 | } 156 | else { 157 | hideViewPager(); 158 | } 159 | } 160 | 161 | 162 | 163 | @Override 164 | public void onClick(View view) { 165 | // TODO Auto-generated method stub 166 | switch (view.getId()) { 167 | case R.id.post_back: 168 | // showSaveDialog(); 169 | break; 170 | case R.id.header_bar_photo_back: 171 | case R.id.header_bar_photo_count: 172 | hideViewPager(); 173 | break; 174 | case R.id.header_bar_photo_delete: 175 | final int index = viewpager.getCurrentItem(); 176 | // new AlertDialog(this).builder() 177 | // .setTitle("提示") 178 | // .setMsg("要删除这张照片吗?") 179 | // .setNegativeButton("取消", new OnClickListener() { 180 | // 181 | // @Override 182 | // public void onClick(View arg0) { 183 | // // TODO Auto-generated method stub 184 | // 185 | // } 186 | // }) 187 | // .setPositiveButton("确定", new OnClickListener() { 188 | // 189 | // @Override 190 | // public void onClick(View arg0) { 191 | // // TODO Auto-generated method stub 192 | // pictures.remove(index); 193 | // if (pictures.size() == 9) { 194 | // add.setVisibility(View.GONE); 195 | // } else { 196 | // add.setVisibility(View.VISIBLE); 197 | // } 198 | // if (pictures.size() == 0) { 199 | // hideViewPager(); 200 | // } 201 | // picContainer.removeView(picContainer.getChildAt(index)); 202 | // picRemain.setText(pictures.size() + "/9"); 203 | // mCountView.setText((viewpager.getCurrentItem() + 1) + "/" + pictures.size()); 204 | // viewpager.getAdapter().notifyDataSetChanged(); 205 | // LocalImageHelper.getInstance().setCurrentSize(pictures.size()); 206 | // } 207 | // }).show(); 208 | 209 | break; 210 | case R.id.post_send: 211 | imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 212 | String content = mContent.getText().toString(); 213 | if (StringUtils.isEmpty(content) && pictures.isEmpty()) { 214 | Toast.makeText(this, "请添写动态内容或至少添加一张图片", Toast.LENGTH_SHORT).show(); 215 | return; 216 | } else { 217 | //设置为不可点击,防止重复提交 218 | view.setEnabled(false); 219 | } 220 | break; 221 | case R.id.post_add_pic: 222 | Intent intent = new Intent(DynamicPost.this, LocalAlbum.class); 223 | startActivityForResult(intent, ImageUtils.REQUEST_CODE_GETIMAGE_BYCROP); 224 | break; 225 | default: 226 | if (view instanceof FilterImageView) { 227 | for (int i = 0; i < picContainer.getChildCount(); i++) { 228 | if (view == picContainer.getChildAt(i)) { 229 | showViewPager(i); 230 | } 231 | } 232 | } 233 | break; 234 | } 235 | } 236 | 237 | 238 | 239 | 240 | 241 | private OnPageChangeListener pageChangeListener = new OnPageChangeListener() { 242 | 243 | @Override 244 | public void onPageSelected(int position) { 245 | if (viewpager.getAdapter() != null) { 246 | String text = (position + 1) + "/" + viewpager.getAdapter().getCount(); 247 | mCountView.setText(text); 248 | } else { 249 | mCountView.setText("0/0"); 250 | } 251 | } 252 | 253 | @Override 254 | public void onPageScrolled(int arg0, float arg1, int arg2) { 255 | // TODO Auto-generated method stub 256 | 257 | } 258 | 259 | @Override 260 | public void onPageScrollStateChanged(int arg0) { 261 | // TODO Auto-generated method stub 262 | 263 | } 264 | }; 265 | 266 | //显示大图pager 267 | private void showViewPager(int index) { 268 | pagerContainer.setVisibility(View.VISIBLE); 269 | editContainer.setVisibility(View.GONE); 270 | viewpager.setAdapter(viewpager.new LocalViewPagerAdapter(pictures)); 271 | viewpager.setCurrentItem(index); 272 | mCountView.setText((index + 1) + "/" + pictures.size()); 273 | AnimationSet set = new AnimationSet(true); 274 | ScaleAnimation scaleAnimation = new ScaleAnimation((float) 0.9, 1, (float) 0.9, 1, pagerContainer.getWidth() / 2, pagerContainer.getHeight() / 2); 275 | scaleAnimation.setDuration(200); 276 | set.addAnimation(scaleAnimation); 277 | AlphaAnimation alphaAnimation = new AlphaAnimation((float) 0.1, 1); 278 | alphaAnimation.setDuration(200); 279 | set.addAnimation(alphaAnimation); 280 | pagerContainer.startAnimation(set); 281 | } 282 | 283 | //关闭大图显示 284 | private void hideViewPager() { 285 | pagerContainer.setVisibility(View.GONE); 286 | editContainer.setVisibility(View.VISIBLE); 287 | AnimationSet set = new AnimationSet(true); 288 | ScaleAnimation scaleAnimation = new ScaleAnimation(1, (float) 0.9, 1, (float) 0.9, pagerContainer.getWidth() / 2, pagerContainer.getHeight() / 2); 289 | scaleAnimation.setDuration(200); 290 | set.addAnimation(scaleAnimation); 291 | AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); 292 | alphaAnimation.setDuration(200); 293 | set.addAnimation(alphaAnimation); 294 | pagerContainer.startAnimation(set); 295 | } 296 | 297 | @Override 298 | public void onSingleTap() { 299 | hideViewPager(); 300 | } 301 | 302 | 303 | @Override 304 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 305 | switch (requestCode) { 306 | case ImageUtils.REQUEST_CODE_GETIMAGE_BYCROP: 307 | if (LocalImageHelper.getInstance().isResultOk()) { 308 | LocalImageHelper.getInstance().setResultOk(false); 309 | //获取选中的图片 310 | List files = LocalImageHelper.getInstance().getCheckedItems(); 311 | for (int i = 0; i < files.size(); i++) { 312 | LayoutParams params = new LayoutParams(size, size); 313 | params.rightMargin = padding; 314 | FilterImageView imageView = new FilterImageView(this); 315 | imageView.setLayoutParams(params); 316 | imageView.setScaleType(ScaleType.CENTER_CROP); 317 | ImageLoader.getInstance().displayImage(files.get(i).getThumbnailUri(), new ImageViewAware(imageView), options, 318 | null, null, files.get(i).getOrientation()); 319 | imageView.setOnClickListener(this); 320 | pictures.add(files.get(i)); 321 | if (pictures.size() == 9) { 322 | add.setVisibility(View.GONE); 323 | } else { 324 | add.setVisibility(View.VISIBLE); 325 | } 326 | picContainer.addView(imageView, picContainer.getChildCount() - 1); 327 | picRemain.setText(pictures.size() + "/9"); 328 | LocalImageHelper.getInstance().setCurrentSize(pictures.size()); 329 | } 330 | //清空选中的图片 331 | files.clear(); 332 | //设置当前选中的图片数量 333 | LocalImageHelper.getInstance().setCurrentSize(pictures.size()); 334 | //延迟滑动至最右边 335 | new Handler().postDelayed(new Runnable() { 336 | public void run() { 337 | scrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT); 338 | } 339 | }, 50L); 340 | } 341 | //清空选中的图片 342 | LocalImageHelper.getInstance().getCheckedItems().clear(); 343 | break; 344 | default: 345 | break; 346 | } 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/ui/LocalAlbumDetail.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.ui; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Color; 6 | import android.graphics.PorterDuff; 7 | import android.os.Bundle; 8 | import android.support.v4.view.ViewPager; 9 | import android.text.TextUtils; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.view.animation.AlphaAnimation; 14 | import android.view.animation.AnimationSet; 15 | import android.view.animation.ScaleAnimation; 16 | import android.widget.BaseAdapter; 17 | import android.widget.CheckBox; 18 | import android.widget.CompoundButton; 19 | import android.widget.GridView; 20 | import android.widget.ImageView; 21 | import android.widget.TextView; 22 | import android.widget.Toast; 23 | 24 | 25 | import com.example.localalbum.AppContext; 26 | import com.example.localalbum.AppManager; 27 | import com.example.localalbum.R; 28 | import com.example.localalbum.common.ExtraKey; 29 | import com.example.localalbum.common.LocalImageHelper; 30 | import com.example.localalbum.widget.AlbumViewPager; 31 | import com.example.localalbum.widget.MatrixImageView; 32 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 33 | import com.nostra13.universalimageloader.core.ImageLoader; 34 | import com.nostra13.universalimageloader.core.assist.ImageSize; 35 | import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer; 36 | import com.nostra13.universalimageloader.core.imageaware.ImageViewAware; 37 | import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; 38 | 39 | import java.util.List; 40 | 41 | 42 | /** 43 | * @author linjizong 44 | * @Description:欢迎页测试 45 | * @date 2015-4-11 46 | */ 47 | public class LocalAlbumDetail extends BaseActivity implements MatrixImageView.OnSingleTapListener, View.OnClickListener 48 | ,CompoundButton.OnCheckedChangeListener{ 49 | 50 | GridView gridView; 51 | TextView title;//标题 52 | View titleBar;//标题栏 53 | View pagerContainer;//图片显示部分 54 | TextView finish,headerFinish; 55 | AlbumViewPager viewpager;//大图显示pager 56 | String folder; 57 | TextView mCountView; 58 | List currentFolder = null; 59 | 60 | ImageView mBackView; 61 | View headerBar; 62 | CheckBox checkBox; 63 | LocalImageHelper helper = LocalImageHelper.getInstance(); 64 | List checkedItems ; 65 | @Override 66 | protected void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | setContentView(R.layout.local_album_detail); 69 | if(!LocalImageHelper.getInstance().isInited()){ 70 | finish(); 71 | return; 72 | } 73 | title = (TextView) findViewById(R.id.album_title); 74 | finish = (TextView) findViewById(R.id.album_finish); 75 | headerFinish=(TextView)findViewById(R.id.header_finish); 76 | gridView = (GridView) findViewById(R.id.gridview); 77 | titleBar = findViewById(R.id.album_title_bar); 78 | viewpager = (AlbumViewPager) findViewById(R.id.albumviewpager); 79 | pagerContainer = findViewById(R.id.pagerview); 80 | mCountView = (TextView) findViewById(R.id.header_bar_photo_count); 81 | viewpager.setOnPageChangeListener(pageChangeListener); 82 | viewpager.setOnSingleTapListener(this); 83 | mBackView = (ImageView) findViewById(R.id.header_bar_photo_back); 84 | headerBar =findViewById(R.id.album_item_header_bar); 85 | checkBox= (CheckBox) findViewById(R.id.checkbox); 86 | checkBox.setOnCheckedChangeListener(this); 87 | mBackView.setOnClickListener(this); 88 | finish.setOnClickListener(this); 89 | headerFinish.setOnClickListener(this); 90 | findViewById(R.id.album_back).setOnClickListener(this); 91 | 92 | folder = getIntent().getExtras().getString(ExtraKey.LOCAL_FOLDER_NAME); 93 | new Thread(new Runnable() { 94 | @Override 95 | public void run() { 96 | //防止停留在本界面时切换到桌面,导致应用被回收,图片数组被清空,在此处做一个初始化处理 97 | helper.initImage(); 98 | //获取该文件夹下地所有文件 99 | final List folders = helper.getFolder(folder); 100 | runOnUiThread(new Runnable() { 101 | @Override 102 | public void run() { 103 | if (folders != null) { 104 | currentFolder = folders; 105 | MyAdapter adapter = new MyAdapter(LocalAlbumDetail.this, folders); 106 | title.setText(folder); 107 | gridView.setAdapter(adapter); 108 | //设置当前选中数量 109 | if (checkedItems.size()+LocalImageHelper.getInstance().getCurrentSize() > 0) { 110 | finish.setText("完成(" + (checkedItems.size()+LocalImageHelper.getInstance().getCurrentSize()) + "/9)"); 111 | finish.setEnabled(true); 112 | headerFinish.setText("完成(" + (checkedItems.size()+LocalImageHelper.getInstance().getCurrentSize()) + "/9)"); 113 | headerFinish.setEnabled(true); 114 | } else { 115 | finish.setText("完成"); 116 | // finish.setEnabled(false); 117 | headerFinish.setText("完成"); 118 | // headerFinish.setEnabled(false); 119 | } 120 | } 121 | } 122 | }); 123 | } 124 | }).start(); 125 | checkedItems=helper.getCheckedItems(); 126 | LocalImageHelper.getInstance().setResultOk(false); 127 | } 128 | 129 | 130 | private void showViewPager(int index) { 131 | pagerContainer.setVisibility(View.VISIBLE); 132 | gridView.setVisibility(View.GONE); 133 | findViewById(R.id.album_title_bar).setVisibility(View.GONE); 134 | viewpager.setAdapter(viewpager.new LocalViewPagerAdapter(currentFolder)); 135 | viewpager.setCurrentItem(index); 136 | mCountView.setText((index + 1) + "/" + currentFolder.size()); 137 | //第一次载入第一张图时,需要手动修改 138 | if(index==0){ 139 | checkBox.setTag(currentFolder.get(index)); 140 | checkBox.setChecked(checkedItems.contains(currentFolder.get(index))); 141 | } 142 | AnimationSet set = new AnimationSet(true); 143 | ScaleAnimation scaleAnimation = new ScaleAnimation((float) 0.9, 1, (float) 0.9, 1, pagerContainer.getWidth() / 2, pagerContainer.getHeight() / 2); 144 | scaleAnimation.setDuration(300); 145 | set.addAnimation(scaleAnimation); 146 | AlphaAnimation alphaAnimation = new AlphaAnimation((float) 0.1, 1); 147 | alphaAnimation.setDuration(200); 148 | set.addAnimation(alphaAnimation); 149 | pagerContainer.startAnimation(set); 150 | } 151 | 152 | private void hideViewPager() { 153 | pagerContainer.setVisibility(View.GONE); 154 | gridView.setVisibility(View.VISIBLE); 155 | findViewById(R.id.album_title_bar).setVisibility(View.VISIBLE); 156 | AnimationSet set = new AnimationSet(true); 157 | ScaleAnimation scaleAnimation = new ScaleAnimation(1, (float) 0.9, 1, (float) 0.9, pagerContainer.getWidth() / 2, pagerContainer.getHeight() / 2); 158 | scaleAnimation.setDuration(200); 159 | set.addAnimation(scaleAnimation); 160 | AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0); 161 | alphaAnimation.setDuration(200); 162 | set.addAnimation(alphaAnimation); 163 | pagerContainer.startAnimation(set); 164 | ((BaseAdapter)gridView.getAdapter()).notifyDataSetChanged(); 165 | } 166 | 167 | private ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() { 168 | 169 | @Override 170 | public void onPageSelected(int position) { 171 | if (viewpager.getAdapter() != null) { 172 | String text = (position + 1) + "/" + viewpager.getAdapter().getCount(); 173 | mCountView.setText(text); 174 | checkBox.setTag(currentFolder.get(position)); 175 | checkBox.setChecked(checkedItems.contains(currentFolder.get(position))); 176 | } else { 177 | mCountView.setText("0/0"); 178 | } 179 | } 180 | 181 | @Override 182 | public void onPageScrolled(int arg0, float arg1, int arg2) { 183 | // TODO Auto-generated method stub 184 | 185 | } 186 | 187 | @Override 188 | public void onPageScrollStateChanged(int arg0) { 189 | // TODO Auto-generated method stub 190 | 191 | } 192 | }; 193 | 194 | @Override 195 | public void onSingleTap() { 196 | if (headerBar.getVisibility() == View.VISIBLE) { 197 | AlphaAnimation animation=new AlphaAnimation(1, 0); 198 | animation.setDuration(300); 199 | headerBar.startAnimation(animation); 200 | headerBar.setVisibility(View.GONE); 201 | } 202 | else { 203 | headerBar.setVisibility(View.VISIBLE); 204 | AlphaAnimation animation=new AlphaAnimation(0, 1); 205 | animation.setDuration(300); 206 | headerBar.startAnimation(animation); 207 | } 208 | } 209 | 210 | @Override 211 | public void onClick(View view) { 212 | switch (view.getId()) { 213 | case R.id.header_bar_photo_back: 214 | hideViewPager(); 215 | break; 216 | case R.id.album_finish: 217 | case R.id.header_finish: 218 | AppManager.getAppManager().finishActivity(LocalAlbum.class); 219 | LocalImageHelper.getInstance().setResultOk(true); 220 | finish(); 221 | break; 222 | case R.id.album_back: 223 | finish(); 224 | break; 225 | } 226 | } 227 | @Override 228 | public void onBackPressed() { 229 | if(pagerContainer.getVisibility()==View.VISIBLE){ 230 | hideViewPager(); 231 | } 232 | else { 233 | super.onBackPressed(); 234 | } 235 | } 236 | 237 | @Override 238 | public void onCheckedChanged(CompoundButton compoundButton, boolean b) { 239 | if (!b) { 240 | if (checkedItems.contains(compoundButton.getTag())) { 241 | checkedItems.remove(compoundButton.getTag()); 242 | } 243 | } else { 244 | if (!checkedItems.contains(compoundButton.getTag())) { 245 | if(checkedItems.size()+LocalImageHelper.getInstance().getCurrentSize()>=9){ 246 | Toast.makeText(this,"最多选择9张图片",Toast.LENGTH_SHORT).show(); 247 | compoundButton.setChecked(false); 248 | return; 249 | } 250 | checkedItems.add((LocalImageHelper.LocalFile) compoundButton.getTag()); 251 | } 252 | } 253 | if (checkedItems.size()+ LocalImageHelper.getInstance().getCurrentSize()> 0) { 254 | finish.setText("完成(" + (checkedItems.size()+LocalImageHelper.getInstance().getCurrentSize()) + "/9)"); 255 | finish.setEnabled(true); 256 | headerFinish.setText("完成(" +(checkedItems.size()+LocalImageHelper.getInstance().getCurrentSize()) + "/9)"); 257 | headerFinish.setEnabled(true); 258 | } else { 259 | finish.setText("完成"); 260 | finish.setEnabled(false); 261 | headerFinish.setText("完成"); 262 | headerFinish.setEnabled(false); 263 | } 264 | } 265 | 266 | public class MyAdapter extends BaseAdapter{ 267 | private Context m_context; 268 | private LayoutInflater miInflater; 269 | DisplayImageOptions options; 270 | List paths; 271 | 272 | public MyAdapter(Context context, List paths) { 273 | m_context = context; 274 | this.paths = paths; 275 | options=new DisplayImageOptions.Builder() 276 | .cacheInMemory(true) 277 | .cacheOnDisk(false) 278 | .showImageForEmptyUri(R.drawable.dangkr_no_picture_small) 279 | .showImageOnFail(R.drawable.dangkr_no_picture_small) 280 | .showImageOnLoading(R.drawable.dangkr_no_picture_small) 281 | .bitmapConfig(Bitmap.Config.RGB_565) 282 | .setImageSize(new ImageSize(((AppContext) context.getApplicationContext()).getQuarterWidth(), 0)) 283 | .displayer(new SimpleBitmapDisplayer()).build(); 284 | } 285 | 286 | @Override 287 | public int getCount() { 288 | return paths.size(); 289 | } 290 | 291 | @Override 292 | public LocalImageHelper.LocalFile getItem(int i) { 293 | return paths.get(i); 294 | } 295 | 296 | @Override 297 | public long getItemId(int i) { 298 | return 0; 299 | } 300 | 301 | @Override 302 | public View getView(final int i, View convertView, ViewGroup viewGroup) { 303 | ViewHolder viewHolder = new ViewHolder(); 304 | 305 | if (convertView == null || convertView.getTag() == null) { 306 | viewHolder = new ViewHolder(); 307 | LayoutInflater inflater = getLayoutInflater(); 308 | convertView = inflater.inflate(R.layout.simple_list_item, null); 309 | viewHolder.imageView = (ImageView) convertView.findViewById(R.id.imageView); 310 | viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox); 311 | viewHolder.checkBox.setOnCheckedChangeListener(LocalAlbumDetail.this); 312 | convertView.setTag(viewHolder); 313 | } else { 314 | viewHolder = (ViewHolder) convertView.getTag(); 315 | } 316 | ImageView imageView = viewHolder.imageView; 317 | LocalImageHelper.LocalFile localFile = paths.get(i); 318 | // FrescoLoader.getInstance().localDisplay(localFile.getThumbnailUri(), imageView, options); 319 | ImageLoader.getInstance().displayImage(localFile.getThumbnailUri(), new ImageViewAware(viewHolder.imageView), options, 320 | loadingListener, null, localFile.getOrientation()); 321 | viewHolder.checkBox.setTag(localFile); 322 | viewHolder.checkBox.setChecked(checkedItems.contains(localFile)); 323 | viewHolder.imageView.setOnClickListener(new View.OnClickListener() { 324 | @Override 325 | public void onClick(View view) { 326 | showViewPager(i); 327 | } 328 | }); 329 | return convertView; 330 | } 331 | 332 | private class ViewHolder { 333 | ImageView imageView; 334 | CheckBox checkBox; 335 | } 336 | } 337 | 338 | SimpleImageLoadingListener loadingListener=new SimpleImageLoadingListener() { 339 | @Override 340 | public void onLoadingComplete(String imageUri, View view, final Bitmap bm) { 341 | if (TextUtils.isEmpty(imageUri)) { 342 | return; 343 | } 344 | //由于很多图片是白色背景,在此处加一个#eeeeee的滤镜,防止checkbox看不清 345 | try { 346 | ((ImageView) view).getDrawable().setColorFilter(Color.argb(0xff, 0xee, 0xee, 0xee), PorterDuff.Mode.MULTIPLY); 347 | } catch (Exception e) { 348 | e.printStackTrace(); 349 | } 350 | } 351 | }; 352 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/localalbum/common/ImageUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.localalbum.common; 2 | 3 | import android.app.Activity; 4 | import android.content.ContentResolver; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.database.Cursor; 8 | import android.graphics.Bitmap; 9 | import android.graphics.Bitmap.CompressFormat; 10 | import android.graphics.Bitmap.Config; 11 | import android.graphics.BitmapFactory; 12 | import android.graphics.Canvas; 13 | import android.graphics.LinearGradient; 14 | import android.graphics.Matrix; 15 | import android.graphics.Paint; 16 | import android.graphics.PixelFormat; 17 | import android.graphics.PorterDuff.Mode; 18 | import android.graphics.PorterDuffXfermode; 19 | import android.graphics.Rect; 20 | import android.graphics.RectF; 21 | import android.graphics.Shader.TileMode; 22 | import android.graphics.drawable.BitmapDrawable; 23 | import android.graphics.drawable.Drawable; 24 | import android.net.Uri; 25 | import android.os.Environment; 26 | import android.provider.MediaStore; 27 | import android.provider.MediaStore.MediaColumns; 28 | import android.util.DisplayMetrics; 29 | 30 | 31 | import com.example.localalbum.AppContext; 32 | 33 | import java.io.BufferedOutputStream; 34 | import java.io.ByteArrayOutputStream; 35 | import java.io.File; 36 | import java.io.FileInputStream; 37 | import java.io.FileNotFoundException; 38 | import java.io.FileOutputStream; 39 | import java.io.IOException; 40 | import java.io.InputStream; 41 | import java.io.OutputStream; 42 | import java.sql.Timestamp; 43 | import java.text.SimpleDateFormat; 44 | 45 | /** 46 | * 图片操作工具包 47 | * 48 | * @author liux (http://my.oschina.net/liux) 49 | * @version 1.0 50 | * @created 2012-3-21 51 | */ 52 | public class ImageUtils { 53 | 54 | public final static String SDCARD_MNT = "/mnt/sdcard"; 55 | public final static String SDCARD = "/sdcard"; 56 | 57 | /** 请求相册 */ 58 | public static final int REQUEST_CODE_GETIMAGE_BYSDCARD = 0; 59 | /** 请求相机 */ 60 | public static final int REQUEST_CODE_GETIMAGE_BYCAMERA = 1; 61 | /** 请求裁剪 */ 62 | public static final int REQUEST_CODE_GETIMAGE_BYCROP = 2; 63 | 64 | /** 65 | * 写图片文件 在Android系统中,文件保存在 /data/data/PACKAGE_NAME/files 目录下 66 | * 67 | * @throws IOException 68 | */ 69 | public static void saveImage(Context context, String fileName, Bitmap bitmap) 70 | throws IOException { 71 | saveImage(context, fileName, bitmap, 100); 72 | } 73 | 74 | public static void saveImage(Context context, String fileName, 75 | Bitmap bitmap, int quality) throws IOException { 76 | if (bitmap == null || fileName == null || context == null) 77 | return; 78 | 79 | FileOutputStream fos = context.openFileOutput(fileName, 80 | Context.MODE_PRIVATE); 81 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 82 | bitmap.compress(CompressFormat.JPEG, quality, stream); 83 | byte[] bytes = stream.toByteArray(); 84 | fos.write(bytes); 85 | fos.close(); 86 | } 87 | 88 | /** 89 | * 写图片文件到SD卡 90 | * 91 | * @throws IOException 92 | */ 93 | public static void saveImageToSD(Context ctx, String filePath, 94 | Bitmap bitmap, int quality) throws IOException { 95 | if (bitmap != null) { 96 | File file = new File(filePath.substring(0, 97 | filePath.lastIndexOf(File.separator))); 98 | if (!file.exists()) { 99 | file.mkdirs(); 100 | } 101 | BufferedOutputStream bos = new BufferedOutputStream( 102 | new FileOutputStream(filePath)); 103 | bitmap.compress(CompressFormat.JPEG, quality, bos); 104 | bos.flush(); 105 | bos.close(); 106 | if (ctx != null) { 107 | scanPhoto(ctx, filePath); 108 | } 109 | } 110 | } 111 | 112 | public static void saveBackgroundImage(Context ctx, String filePath, 113 | Bitmap bitmap, int quality) throws IOException { 114 | if (bitmap != null) { 115 | File file = new File(filePath.substring(0, 116 | filePath.lastIndexOf(File.separator))); 117 | if (!file.exists()) { 118 | file.mkdirs(); 119 | } 120 | BufferedOutputStream bos = new BufferedOutputStream( 121 | new FileOutputStream(filePath)); 122 | bitmap.compress(CompressFormat.PNG, quality, bos); 123 | bos.flush(); 124 | bos.close(); 125 | if (ctx != null) { 126 | scanPhoto(ctx, filePath); 127 | } 128 | } 129 | } 130 | 131 | /** 132 | * 让Gallery上能马上看到该图片 133 | */ 134 | private static void scanPhoto(Context ctx, String imgFileName) { 135 | Intent mediaScanIntent = new Intent( 136 | Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); 137 | File file = new File(imgFileName); 138 | Uri contentUri = Uri.fromFile(file); 139 | mediaScanIntent.setData(contentUri); 140 | ctx.sendBroadcast(mediaScanIntent); 141 | } 142 | 143 | /** 144 | * 获取bitmap 145 | * 146 | * @param context 147 | * @param fileName 148 | * @return 149 | */ 150 | public static Bitmap getBitmap(Context context, String fileName) { 151 | FileInputStream fis = null; 152 | Bitmap bitmap = null; 153 | try { 154 | fis = context.openFileInput(fileName); 155 | bitmap = BitmapFactory.decodeStream(fis); 156 | } catch (FileNotFoundException e) { 157 | e.printStackTrace(); 158 | } catch (OutOfMemoryError e) { 159 | e.printStackTrace(); 160 | } finally { 161 | try { 162 | fis.close(); 163 | } catch (Exception e) { 164 | } 165 | } 166 | return bitmap; 167 | } 168 | 169 | /** 170 | * 获取bitmap 171 | * 172 | * @param filePath 173 | * @return 174 | */ 175 | public static Bitmap getBitmapByPath(String filePath) { 176 | return getBitmapByPath(filePath, null); 177 | } 178 | 179 | public static Bitmap getBitmapByPath(String filePath, 180 | BitmapFactory.Options opts) { 181 | FileInputStream fis = null; 182 | Bitmap bitmap = null; 183 | try { 184 | File file = new File(filePath); 185 | fis = new FileInputStream(file); 186 | bitmap = BitmapFactory.decodeStream(fis, null, opts); 187 | } catch (FileNotFoundException e) { 188 | e.printStackTrace(); 189 | } catch (OutOfMemoryError e) { 190 | e.printStackTrace(); 191 | } finally { 192 | try { 193 | fis.close(); 194 | } catch (Exception e) { 195 | } 196 | } 197 | return bitmap; 198 | } 199 | 200 | /** 201 | * 获取bitmap 202 | * 203 | * @param file 204 | * @return 205 | */ 206 | public static Bitmap getBitmapByFile(File file) { 207 | FileInputStream fis = null; 208 | Bitmap bitmap = null; 209 | try { 210 | fis = new FileInputStream(file); 211 | bitmap = BitmapFactory.decodeStream(fis); 212 | } catch (FileNotFoundException e) { 213 | e.printStackTrace(); 214 | } catch (OutOfMemoryError e) { 215 | e.printStackTrace(); 216 | } finally { 217 | try { 218 | fis.close(); 219 | } catch (Exception e) { 220 | } 221 | } 222 | return bitmap; 223 | } 224 | 225 | /** 226 | * 使用当前时间戳拼接一个唯一的文件名 227 | * 228 | * @return 229 | */ 230 | public static String getTempFileName() { 231 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss_SS"); 232 | String fileName = format.format(new Timestamp(System 233 | .currentTimeMillis())); 234 | return fileName; 235 | } 236 | 237 | /** 238 | * 获取照相机使用的目录 239 | * 240 | * @return 241 | */ 242 | public static String getCamerPath() { 243 | return Environment.getExternalStorageDirectory() + File.separator 244 | + "FounderNews" + File.separator; 245 | } 246 | 247 | /** 248 | * 判断当前Url是否标准的content://样式,如果不是,则返回绝对路径 249 | * 250 | * @return 251 | */ 252 | public static String getAbsolutePathFromNoStandardUri(Uri mUri) { 253 | String filePath = null; 254 | 255 | String mUriString = mUri.toString(); 256 | mUriString = Uri.decode(mUriString); 257 | 258 | String pre1 = "file://" + SDCARD + File.separator; 259 | String pre2 = "file://" + SDCARD_MNT + File.separator; 260 | 261 | if (mUriString.startsWith(pre1)) { 262 | filePath = Environment.getExternalStorageDirectory().getPath() 263 | + File.separator + mUriString.substring(pre1.length()); 264 | } else if (mUriString.startsWith(pre2)) { 265 | filePath = Environment.getExternalStorageDirectory().getPath() 266 | + File.separator + mUriString.substring(pre2.length()); 267 | } 268 | return filePath; 269 | } 270 | 271 | /** 272 | * 通过uri获取文件的绝对路径 273 | * 274 | * @param uri 275 | * @return 276 | */ 277 | @SuppressWarnings("deprecation") 278 | public static String getAbsoluteImagePath(Activity context, Uri uri) { 279 | String imagePath = ""; 280 | String[] proj = { MediaStore.Images.Media.DATA }; 281 | Cursor cursor = context.managedQuery(uri, proj, // Which columns to 282 | // return 283 | null, // WHERE clause; which rows to return (all rows) 284 | null, // WHERE clause selection arguments (none) 285 | null); // Order-by clause (ascending by name) 286 | 287 | if (cursor != null) { 288 | int column_index = cursor 289 | .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 290 | if (cursor.getCount() > 0 && cursor.moveToFirst()) { 291 | imagePath = cursor.getString(column_index); 292 | } 293 | } 294 | 295 | return imagePath; 296 | } 297 | 298 | /** 299 | * 获取图片缩略图 只有Android2.1以上版本支持 300 | * 301 | * @param imgName 302 | * @param kind 303 | * MediaStore.Images.Thumbnails.MICRO_KIND 304 | * @return 305 | */ 306 | @SuppressWarnings("deprecation") 307 | public static Bitmap loadImgThumbnail(Activity context, String imgName, 308 | int kind) { 309 | Bitmap bitmap = null; 310 | 311 | String[] proj = { MediaStore.Images.Media._ID, 312 | MediaStore.Images.Media.DISPLAY_NAME }; 313 | 314 | Cursor cursor = context.managedQuery( 315 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, proj, 316 | MediaStore.Images.Media.DISPLAY_NAME + "='" + imgName + "'", 317 | null, null); 318 | 319 | if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) { 320 | ContentResolver crThumb = context.getContentResolver(); 321 | BitmapFactory.Options options = new BitmapFactory.Options(); 322 | options.inSampleSize = 1; 323 | bitmap = MethodsCompat.getThumbnail(crThumb, cursor.getInt(0), 324 | kind, options); 325 | } 326 | return bitmap; 327 | } 328 | 329 | public static Bitmap loadImgThumbnail(String filePath, int w, int h) { 330 | Bitmap bitmap = getBitmapByPath(filePath); 331 | return zoomBitmap(bitmap, w, h,0); 332 | } 333 | 334 | /** 335 | * 获取SD卡中最新图片路径 336 | * 337 | * @return 338 | */ 339 | public static String getLatestImage(Activity context) { 340 | String latestImage = null; 341 | String[] items = { MediaStore.Images.Media._ID, 342 | MediaStore.Images.Media.DATA }; 343 | Cursor cursor = context.managedQuery( 344 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, items, null, 345 | null, MediaStore.Images.Media._ID + " desc"); 346 | 347 | if (cursor != null && cursor.getCount() > 0) { 348 | cursor.moveToFirst(); 349 | for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor 350 | .moveToNext()) { 351 | latestImage = cursor.getString(1); 352 | break; 353 | } 354 | } 355 | 356 | return latestImage; 357 | } 358 | 359 | /** 360 | * 计算缩放图片的宽高 361 | * 362 | * @param img_size 363 | * @param square_size 364 | * @return 365 | */ 366 | public static int[] scaleImageSize(int[] img_size, int square_size) { 367 | if (img_size[0] <= square_size && img_size[1] <= square_size) 368 | return img_size; 369 | double ratio = square_size 370 | / (double) Math.max(img_size[0], img_size[1]); 371 | return new int[] { (int) (img_size[0] * ratio), 372 | (int) (img_size[1] * ratio) }; 373 | } 374 | 375 | /** 376 | * 创建缩略图 377 | * 378 | * @param context 379 | * @param largeImagePath 380 | * 原始大图路径 381 | * @param thumbfilePath 382 | * 输出缩略图路径 383 | * @param square_size 384 | * 输出图片宽度 385 | * @param quality 386 | * 输出图片质量 387 | * @throws IOException 388 | */ 389 | public static void createImageThumbnail(Context context, 390 | String largeImagePath, String thumbfilePath, int square_size, 391 | int quality,int rotate) throws IOException { 392 | BitmapFactory.Options options = new BitmapFactory.Options(); 393 | options.inJustDecodeBounds = true; 394 | BitmapFactory.decodeFile(largeImagePath, options); 395 | options.inSampleSize = caculateInSampleSize(options, 396 | square_size, square_size); 397 | 398 | // 使用获得到的InSampleSize再次解析图片 399 | options.inJustDecodeBounds = false; 400 | // 原始图片bitmap 401 | Bitmap cur_bitmap = getBitmapByPath(largeImagePath, options); 402 | 403 | if (cur_bitmap == null) 404 | return; 405 | 406 | // 原始图片的高宽 407 | // int[] cur_img_size = new int[] { cur_bitmap.getWidth(), 408 | // cur_bitmap.getHeight() }; 409 | // 计算原始图片缩放后的宽高 410 | // int[] new_img_size = scaleImageSize(cur_img_size, square_size); 411 | // 生成缩放后的bitmap 412 | // Bitmap thb_bitmap = zoomBitmap(cur_bitmap, new_img_size[0], 413 | // new_img_size[1],rotate); 414 | // 生成缩放后的图片文件 415 | saveImageToSD(null, thumbfilePath, cur_bitmap, quality); 416 | } 417 | private static int caculateInSampleSize(BitmapFactory.Options options, 418 | int reqWidth, int reqHeight) { 419 | final int height = options.outHeight; 420 | final int width = options.outWidth; 421 | int inSampleSize = 1; 422 | if (height > reqHeight || width > reqWidth) { 423 | final int halfHeight = height ; 424 | final int halfWidth = width ; 425 | while ((halfHeight / inSampleSize) > reqHeight 426 | && (halfWidth / inSampleSize) > reqWidth) { 427 | inSampleSize *= 2; 428 | } 429 | } 430 | return inSampleSize; 431 | } 432 | /** 433 | * 放大缩小图片 434 | * 435 | * @param bitmap 436 | * @param w 437 | * @param h 438 | * @return 439 | */ 440 | public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h,int rotate) { 441 | Bitmap newbmp = null; 442 | if (bitmap != null) { 443 | int width = bitmap.getWidth(); 444 | int height = bitmap.getHeight(); 445 | Matrix matrix = new Matrix(); 446 | float scaleWidht = ((float) w / width); 447 | float scaleHeight = ((float) h / height); 448 | matrix.postScale(scaleWidht, scaleHeight); 449 | matrix.postRotate(rotate); 450 | newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, 451 | true); 452 | } 453 | return newbmp; 454 | } 455 | 456 | public static Bitmap scaleBitmap(Bitmap bitmap) { 457 | // 获取这个图片的宽和高 458 | int width = bitmap.getWidth(); 459 | int height = bitmap.getHeight(); 460 | // 定义预转换成的图片的宽度和高度 461 | int newWidth = 200; 462 | int newHeight = 200; 463 | // 计算缩放率,新尺寸除原始尺寸 464 | float scaleWidth = ((float) newWidth) / width; 465 | float scaleHeight = ((float) newHeight) / height; 466 | // 创建操作图片用的matrix对象 467 | Matrix matrix = new Matrix(); 468 | // 缩放图片动作 469 | matrix.postScale(scaleWidth, scaleHeight); 470 | // 旋转图片 动作 471 | // matrix.postRotate(45); 472 | // 创建新的图片 473 | Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, 474 | matrix, true); 475 | return resizedBitmap; 476 | } 477 | 478 | /** 479 | * (缩放)重绘图片 480 | * 481 | * @param context 482 | * Activity 483 | * @param bitmap 484 | * @return 485 | */ 486 | public static Bitmap reDrawBitMap(Activity context, Bitmap bitmap) { 487 | DisplayMetrics dm = new DisplayMetrics(); 488 | context.getWindowManager().getDefaultDisplay().getMetrics(dm); 489 | int rHeight = dm.heightPixels; 490 | int rWidth = dm.widthPixels; 491 | // float rHeight=dm.heightPixels/dm.density+0.5f; 492 | // float rWidth=dm.widthPixels/dm.density+0.5f; 493 | // int height=bitmap.getScaledHeight(dm); 494 | // int width = bitmap.getScaledWidth(dm); 495 | int height = bitmap.getHeight(); 496 | int width = bitmap.getWidth(); 497 | float zoomScale; 498 | 499 | /** 方式3 **/ 500 | if (width >= rWidth) 501 | zoomScale = ((float) rWidth) / width; 502 | else 503 | zoomScale = 1.0f; 504 | // 创建操作图片用的matrix对象 505 | Matrix matrix = new Matrix(); 506 | // 缩放图片动作 507 | matrix.postScale(zoomScale, zoomScale); 508 | Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, 509 | bitmap.getWidth(), bitmap.getHeight(), matrix, true); 510 | return resizedBitmap; 511 | } 512 | 513 | /** 514 | * 将Drawable转化为Bitmap 515 | * 516 | * @param drawable 517 | * @return 518 | */ 519 | public static Bitmap drawableToBitmap(Drawable drawable) { 520 | int width = drawable.getIntrinsicWidth(); 521 | int height = drawable.getIntrinsicHeight(); 522 | Bitmap bitmap = Bitmap.createBitmap(width, height, drawable 523 | .getOpacity() != PixelFormat.OPAQUE ? Config.ARGB_8888 524 | : Config.RGB_565); 525 | Canvas canvas = new Canvas(bitmap); 526 | drawable.setBounds(0, 0, width, height); 527 | drawable.draw(canvas); 528 | return bitmap; 529 | 530 | } 531 | 532 | /** 533 | * 获得圆角图片的方法 534 | * 535 | * @param bitmap 536 | * @param roundPx 537 | * 一般设成14 538 | * @return 539 | */ 540 | public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { 541 | 542 | Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), 543 | bitmap.getHeight(), Config.ARGB_8888); 544 | Canvas canvas = new Canvas(output); 545 | 546 | final int color = 0xff424242; 547 | final Paint paint = new Paint(); 548 | final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 549 | final RectF rectF = new RectF(rect); 550 | 551 | paint.setAntiAlias(true); 552 | canvas.drawARGB(0, 0, 0, 0); 553 | paint.setColor(color); 554 | canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 555 | 556 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 557 | canvas.drawBitmap(bitmap, rect, rect, paint); 558 | 559 | return output; 560 | } 561 | 562 | /** 563 | * 获得带倒影的图片方法 564 | * 565 | * @param bitmap 566 | * @return 567 | */ 568 | public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) { 569 | final int reflectionGap = 4; 570 | int width = bitmap.getWidth(); 571 | int height = bitmap.getHeight(); 572 | 573 | Matrix matrix = new Matrix(); 574 | matrix.preScale(1, -1); 575 | 576 | Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height / 2, 577 | width, height / 2, matrix, false); 578 | 579 | Bitmap bitmapWithReflection = Bitmap.createBitmap(width, 580 | (height + height / 2), Config.ARGB_8888); 581 | 582 | Canvas canvas = new Canvas(bitmapWithReflection); 583 | canvas.drawBitmap(bitmap, 0, 0, null); 584 | Paint deafalutPaint = new Paint(); 585 | canvas.drawRect(0, height, width, height + reflectionGap, deafalutPaint); 586 | 587 | canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null); 588 | 589 | Paint paint = new Paint(); 590 | LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, 591 | bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 592 | 0x00ffffff, TileMode.CLAMP); 593 | paint.setShader(shader); 594 | // Set the Transfer mode to be porter duff and destination in 595 | paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 596 | // Draw a rectangle using the paint with our linear gradient 597 | canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() 598 | + reflectionGap, paint); 599 | 600 | return bitmapWithReflection; 601 | } 602 | 603 | /** 604 | * 将bitmap转化为drawable 605 | * 606 | * @param bitmap 607 | * @return 608 | */ 609 | public static Drawable bitmapToDrawable(Bitmap bitmap) { 610 | Drawable drawable = new BitmapDrawable(bitmap); 611 | return drawable; 612 | } 613 | 614 | /** 615 | * 获取图片类型 616 | * 617 | * @param file 618 | * @return 619 | */ 620 | public static String getImageType(File file) { 621 | if (file == null || !file.exists()) { 622 | return null; 623 | } 624 | InputStream in = null; 625 | try { 626 | in = new FileInputStream(file); 627 | String type = getImageType(in); 628 | return type; 629 | } catch (IOException e) { 630 | return null; 631 | } finally { 632 | try { 633 | if (in != null) { 634 | in.close(); 635 | } 636 | } catch (IOException e) { 637 | } 638 | } 639 | } 640 | 641 | /** 642 | * 获取图片的类型信息 643 | * 644 | * @param in 645 | * @return 646 | * @see #getImageType(byte[]) 647 | */ 648 | public static String getImageType(InputStream in) { 649 | if (in == null) { 650 | return null; 651 | } 652 | try { 653 | byte[] bytes = new byte[8]; 654 | in.read(bytes); 655 | return getImageType(bytes); 656 | } catch (IOException e) { 657 | return null; 658 | } 659 | } 660 | 661 | /** 662 | * 获取图片的类型信息 663 | * 664 | * @param bytes 665 | * 2~8 byte at beginning of the image file 666 | * @return image mimetype or null if the file is not image 667 | */ 668 | public static String getImageType(byte[] bytes) { 669 | if (isJPEG(bytes)) { 670 | return "image/jpeg"; 671 | } 672 | if (isGIF(bytes)) { 673 | return "image/gif"; 674 | } 675 | if (isPNG(bytes)) { 676 | return "image/png"; 677 | } 678 | if (isBMP(bytes)) { 679 | return "application/x-bmp"; 680 | } 681 | return null; 682 | } 683 | 684 | private static boolean isJPEG(byte[] b) { 685 | if (b.length < 2) { 686 | return false; 687 | } 688 | return (b[0] == (byte) 0xFF) && (b[1] == (byte) 0xD8); 689 | } 690 | 691 | private static boolean isGIF(byte[] b) { 692 | if (b.length < 6) { 693 | return false; 694 | } 695 | return b[0] == 'G' && b[1] == 'I' && b[2] == 'F' && b[3] == '8' 696 | && (b[4] == '7' || b[4] == '9') && b[5] == 'a'; 697 | } 698 | 699 | private static boolean isPNG(byte[] b) { 700 | if (b.length < 8) { 701 | return false; 702 | } 703 | return (b[0] == (byte) 137 && b[1] == (byte) 80 && b[2] == (byte) 78 704 | && b[3] == (byte) 71 && b[4] == (byte) 13 && b[5] == (byte) 10 705 | && b[6] == (byte) 26 && b[7] == (byte) 10); 706 | } 707 | 708 | private static boolean isBMP(byte[] b) { 709 | if (b.length < 2) { 710 | return false; 711 | } 712 | return (b[0] == 0x42) && (b[1] == 0x4d); 713 | } 714 | 715 | /** 716 | * 获取图片路径 2014年8月12日 717 | * 718 | * @param uri 719 | * @return E-mail:mr.huangwenwei@gmail.com 720 | */ 721 | public static String getImagePath(Uri uri, Activity context) { 722 | 723 | String[] projection = { MediaColumns.DATA }; 724 | Cursor cursor = context.getContentResolver().query(uri, projection, 725 | null, null, null); 726 | if (cursor != null) { 727 | cursor.moveToFirst(); 728 | int columIndex = cursor.getColumnIndexOrThrow(MediaColumns.DATA); 729 | String ImagePath = cursor.getString(columIndex); 730 | cursor.close(); 731 | return ImagePath; 732 | } 733 | 734 | return uri.toString().replace("file://", ""); 735 | } 736 | 737 | static Bitmap bitmap = null; 738 | /** 739 | *2014年8月13日 740 | *@param uri 741 | *@param context 742 | * E-mail:mr.huangwenwei@gmail.com 743 | */ 744 | public static Bitmap loadPicasaImageFromGalley(final Uri uri, final Activity context) { 745 | 746 | String[] projection = { MediaColumns.DATA, MediaColumns.DISPLAY_NAME }; 747 | Cursor cursor = context.getContentResolver().query(uri, projection, 748 | null, null, null); 749 | if (cursor != null) { 750 | cursor.moveToFirst(); 751 | 752 | int columIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 753 | if (columIndex != -1) { 754 | new Thread(new Runnable() { 755 | 756 | @Override 757 | public void run() { 758 | try { 759 | bitmap = MediaStore.Images.Media 760 | .getBitmap(context.getContentResolver(), 761 | uri); 762 | } catch (FileNotFoundException e) { 763 | e.printStackTrace(); 764 | } catch (IOException e) { 765 | e.printStackTrace(); 766 | } 767 | 768 | } 769 | }).start(); 770 | } 771 | cursor.close(); 772 | return bitmap; 773 | }else 774 | return null; 775 | } 776 | public static File saveBitmap2file(Context context,Bitmap bmp,String filename){ 777 | CompressFormat format= CompressFormat.JPEG; 778 | int quality = 100; 779 | OutputStream stream = null; 780 | try { 781 | stream = new FileOutputStream(AppContext.getInstance().getCachePath()+File.separator + filename); 782 | } catch (FileNotFoundException e) { 783 | // TODO Auto-generated catch block 784 | e.printStackTrace(); 785 | } 786 | 787 | if( bmp.compress(format, quality, stream)){ 788 | return new File(AppContext.getInstance().getCachePath()+File.separator + filename); 789 | } 790 | return null; 791 | 792 | } 793 | public static String getRealFilePath( final Context context, final Uri uri ) { 794 | if ( null == uri ) return null; 795 | final String scheme = uri.getScheme(); 796 | String data = null; 797 | if ( scheme == null ) 798 | data = uri.getPath(); 799 | else if ( ContentResolver.SCHEME_FILE.equals( scheme ) ) { 800 | data = uri.getPath(); 801 | } else if ( ContentResolver.SCHEME_CONTENT.equals( scheme ) ) { 802 | Cursor cursor = context.getContentResolver().query( uri, new String[] { MediaStore.Images.ImageColumns.DATA }, null, null, null ); 803 | if ( null != cursor ) { 804 | if ( cursor.moveToFirst() ) { 805 | int index = cursor.getColumnIndex( MediaStore.Images.ImageColumns.DATA ); 806 | if ( index > -1 ) { 807 | data = cursor.getString( index ); 808 | } 809 | } 810 | cursor.close(); 811 | } 812 | } 813 | return data; 814 | } 815 | } 816 | --------------------------------------------------------------------------------