├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── loopeer │ │ └── android │ │ └── apps │ │ └── imagegroupview │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── loopeer │ │ └── android │ │ └── apps │ │ └── imagegroupview │ │ ├── ImageGroupApp.java │ │ ├── MainActivity.java │ │ └── TestIntentActivity.java │ └── res │ ├── drawable-xxhdpi │ ├── sample_0.jpg │ ├── sample_1.jpg │ ├── sample_2.jpg │ ├── sample_3.jpg │ ├── sample_4.jpg │ ├── sample_5.jpg │ ├── sample_6.jpg │ └── sample_7.jpg │ ├── layout │ ├── activity_main.xml │ └── activity_test_intent.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ └── themes.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── imagegroupview ├── .gitignore ├── bintray.gradle ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── loopeer │ │ └── android │ │ └── apps │ │ └── imagegroupview │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── loopeer │ │ └── android │ │ └── librarys │ │ └── imagegroupview │ │ ├── NavigatorImage.kt │ │ ├── OnImageClickListener.kt │ │ ├── OnTabOneClickListener.kt │ │ ├── activity │ │ ├── AlbumActivity.kt │ │ ├── ImagePickerActivity.java │ │ ├── ImageScaleActivity.java │ │ ├── ImageSwitcherActivity.java │ │ ├── UIPatternActivity.kt │ │ └── UserCameraActivity.java │ │ ├── adapter │ │ ├── AlbumRecyclerAdapter.java │ │ ├── ImageAdapter.java │ │ ├── ImagesSwitcherAdapter.java │ │ └── RecyclerViewAdapter.java │ │ ├── fragment │ │ ├── GetImageDialogFragment.java │ │ └── ScaleImageFragment.java │ │ ├── model │ │ ├── Image.java │ │ ├── ImageFolder.java │ │ ├── ImageSwitcherWrapper.java │ │ └── SquareImage.java │ │ ├── photodraweeview │ │ ├── Attacher.java │ │ ├── DefaultOnDoubleTapListener.java │ │ ├── IAttacher.java │ │ ├── OnPhotoTapListener.java │ │ ├── OnScaleChangeListener.java │ │ ├── OnScaleDragGestureListener.java │ │ ├── OnViewTapListener.java │ │ ├── PhotoDraweeView.java │ │ └── ScaleDragDetector.java │ │ ├── uimanager │ │ ├── IGActivityLifecycleCallbacks.kt │ │ ├── IGLoadHelper.kt │ │ ├── IGRecycler.kt │ │ └── recycler │ │ │ ├── IGLoad.kt │ │ │ ├── IGUIPattern.kt │ │ │ ├── ImageGroupActivityManager.kt │ │ │ └── ImageGroupUIManager.kt │ │ ├── utils │ │ ├── AnimUtils.java │ │ ├── AnimatorScaleType.java │ │ ├── DisplayUtils.java │ │ ├── FileUtils.java │ │ ├── ImageDisplayHelper.java │ │ ├── ImageGroupDisplayHelper.java │ │ ├── ImageGroupSavedState.java │ │ ├── ImageGroupUtils.java │ │ ├── ImageUploadHandler.java │ │ ├── ImageUploadHelper.java │ │ ├── ImageUtils.java │ │ └── PermissionUtils.java │ │ └── view │ │ ├── CustomFragmentPagerAdapter.java │ │ ├── CustomPopupView.java │ │ ├── DividerItemImagesDecoration.java │ │ ├── DragDismissFrameLayout.java │ │ ├── DragRecycleAdapter.java │ │ ├── DragRecycleView.java │ │ ├── ElasticDragDismissFrameLayout.java │ │ ├── FixedNestedScrollView.java │ │ ├── GridImageAdapter.java │ │ ├── ImageGridView.java │ │ ├── ItemTouchHelperAdapter.java │ │ ├── MutipleTouchViewPager.java │ │ ├── ScaleImageView.java │ │ ├── SimpleItemTouchHelperCallback.java │ │ ├── SingleImageView.java │ │ └── SquareImageView.java │ └── res │ ├── anim │ ├── pophidden_anim.xml │ └── popshow_anim.xml │ ├── drawable-xhdpi │ ├── ic_delete.png │ ├── ic_image_delete_icon.png │ └── ic_photo_default.png │ ├── drawable-xxhdpi │ ├── ic_arrow_right.png │ ├── ic_image_default.png │ ├── ic_image_group_camera.png │ ├── ic_image_group_folder_check.png │ ├── ic_image_group_selected.png │ └── ic_image_group_unselected.png │ ├── drawable │ ├── image_group_button_background_primary_corner_selector.xml │ └── selected_image_check_box.xml │ ├── layout │ ├── activity_album.xml │ ├── activity_image_picker.xml │ ├── activity_image_switcher.xml │ ├── activity_images.xml │ ├── activity_scale_image.xml │ ├── dialog_fragment_get_photo.xml │ ├── drag_recycle.xml │ ├── fragment_scale_image.xml │ ├── item_view.xml │ ├── list_item_album.xml │ ├── list_item_camera.xml │ ├── list_item_image.xml │ ├── view_menu_submit.xml │ ├── view_popup_folder.xml │ └── view_recycler_image_group.xml │ ├── menu │ └── menu_image_group_submit.xml │ ├── values-en │ └── strings.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ └── themes.xml ├── screenshot ├── screenshot.gif ├── screenshot_select_animation.gif ├── screenshot_select_photo.gif └── screenshot_witcher.gif ├── settings.gradle └── upload.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Specific files to exclude 2 | dist 3 | com_crashlytics_export_strings.xml 4 | keys.xml 5 | #*.keystore 6 | 7 | ### Android 8 | ########### 9 | # built application files 10 | *.apk 11 | *.ap_ 12 | 13 | # files for the dex VM 14 | *.dex 15 | 16 | # Java class files 17 | *.class 18 | 19 | # generated files 20 | bin/ 21 | gen/ 22 | captures/ 23 | 24 | captures/ 25 | 26 | # Local configuration file (sdk path, etc) 27 | local.properties 28 | keystore.properties 29 | 30 | ### Mac 31 | .DS_store 32 | 33 | ### Linux 34 | ######### 35 | !.gitignore 36 | *~ 37 | 38 | ### Windows 39 | ############ 40 | # Windows image file caches 41 | Thumbs.db 42 | ehthumbs.db 43 | 44 | # Folder config file 45 | Desktop.ini 46 | 47 | # Recycle Bin used on file shares 48 | $RECYCLE.BIN/ 49 | 50 | ### IntelliJ 51 | *.iml 52 | *.ipr 53 | *.iws 54 | .idea/ 55 | 56 | ### Gradle 57 | .gradle/ 58 | build/ 59 | out/ 60 | 61 | #Maven 62 | target 63 | release.properties 64 | pom.xml.* 65 | 66 | ### AppEngine 67 | google_generated/ 68 | datanucleus.log 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ImageGroupView 2 | 3 | This view main solve the view data restore. The activity main killed when open camera. So some data of the group view will not restore by themself. This view save the state and then restore to recreate the layout. 4 | 5 | **Thanks for** 6 | * [Fresco](https://github.com/facebook/fresco) Load image. 7 | * [lovetuzitong/MultiImageSelector](https://github.com/lovetuzitong/MultiImageSelector) Learn the way to get photos. And Use custom view to replace the popupwindow. 8 | * [ongakuer/PhotoDraweeView](https://github.com/ongakuer/PhotoDraweeView) The PhotoView help scale image for Fresco 9 | 10 | Screeshot 11 | ==== 12 | ![](/screenshot/screenshot.gif) 13 | 14 | ![](/screenshot/screenshot_witcher.gif) 15 | 16 | ![](/screenshot/screenshot_select_photo.gif) 17 | 18 | 19 | 20 | Installation 21 | ==== 22 | ```groovy 23 | dependencies { 24 | compile 'com.loopeer.library:imagegroupview:1.0.41' 25 | } 26 | ``` 27 | 28 | Show Images 29 | ==== 30 | First, add the layout 31 | ```xml 32 | 39 | ``` 40 | * **childMargin** The margin between child, as the left and top. 41 | * **column** You can set as you need 42 | * **showAddButton** When set true, you can add image by album or camera 43 | * **addButtonDrawable** 44 | * **imagePlaceholderDrawable** 45 | * **showDeleteText** 46 | * **showDeleteDialog** When set true,there will be a hint when deleting a photo 47 | * **showDeleteButton** 48 | * **deleteDrawable** 49 | 50 | Then, you can add data. 51 | ```java 52 | ArrayList testdata = createTestData()); 53 | imageGroup.setNetworkPhotos(testdata); 54 | ... 55 | imageGroup.setLocalPhotos(testdata); 56 | ... 57 | imageGroup.setPhotosBySquareImage(testdata); 58 | ``` 59 | You can add ClickListener 60 | ```java 61 | imageGroup.setOnImageClickListener(this); 62 | ...... 63 | ``` 64 | Get data by the method 65 | ```java 66 | onImageClick(SquareImage clickImage, ArrayList squareImages, ArrayList allImageInternetUrl) 67 | ``` 68 | Add Images 69 | ==== 70 | If you want to add image, you must add this 71 | ```java 72 | imageGroup.setFragmentManager(getSupportFragmentManager()); 73 | ``` 74 | You must get the data from the intent in the result 75 | ```java 76 | @Override 77 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 78 | super.onActivityResult(requestCode, resultCode, data); 79 | if (resultCode == RESULT_OK) { 80 | imageGroupAddAble.onParentResult(requestCode, data); 81 | } 82 | } 83 | ``` 84 | 85 | License 86 | ==== 87 |
 88 | Copyright 2015 Loopeer
 89 | 
 90 | Licensed under the Apache License, Version 2.0 (the "License");
 91 | you may not use this file except in compliance with the License.
 92 | You may obtain a copy of the License at
 93 | 
 94 |     http://www.apache.org/licenses/LICENSE-2.0
 95 | 
 96 | Unless required by applicable law or agreed to in writing, software
 97 | distributed under the License is distributed on an "AS IS" BASIS,
 98 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 99 | See the License for the specific language governing permissions and
100 | limitations under the License.
101 | 
102 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion Integer.parseInt(compile_sdk_version) 6 | buildToolsVersion build_tools_version 7 | 8 | defaultConfig { 9 | minSdkVersion min_sdk_version 10 | targetSdkVersion target_sdk_version 11 | versionCode Integer.parseInt(version_code) 12 | versionName version_name 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | lintOptions { 22 | abortOnError false 23 | } 24 | 25 | } 26 | 27 | dependencies { 28 | compile fileTree(dir: 'libs', include: ['*.jar']) 29 | compile project(':imagegroupview') 30 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 31 | } 32 | repositories { 33 | mavenCentral() 34 | google() 35 | } 36 | -------------------------------------------------------------------------------- /app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 18 11:10:32 CST 2017 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-4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/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/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/todou/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/loopeer/android/apps/imagegroupview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.apps.imagegroupview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/loopeer/android/apps/imagegroupview/ImageGroupApp.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.apps.imagegroupview; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.drawee.backends.pipeline.Fresco; 6 | import com.facebook.imagepipeline.core.ImagePipelineConfig; 7 | 8 | public class ImageGroupApp extends Application { 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | 13 | ImagePipelineConfig config = ImagePipelineConfig.newBuilder(getApplicationContext()) 14 | .setDownsampleEnabled(true) 15 | .build(); 16 | 17 | Fresco.initialize(this, config); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/loopeer/android/apps/imagegroupview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.apps.imagegroupview; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.view.WindowManager; 8 | 9 | import com.loopeer.android.librarys.imagegroupview.OnImageClickListener; 10 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 11 | import com.loopeer.android.librarys.imagegroupview.view.ImageGridView; 12 | import com.loopeer.android.librarys.imagegroupview.view.SingleImageView; 13 | 14 | import java.util.ArrayList; 15 | 16 | public class MainActivity extends AppCompatActivity implements OnImageClickListener { 17 | 18 | private ImageGridView mGridView; 19 | private ImageGridView mGridView2; 20 | private ImageGridView mGridView3; 21 | private SingleImageView mSingleImageView; 22 | private int gtype = 0; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 28 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 29 | setContentView(R.layout.activity_main); 30 | initGridView(); 31 | } 32 | 33 | 34 | private void initGridView() { 35 | mGridView = (ImageGridView) findViewById(R.id.grid_test_group); 36 | mGridView2 = (ImageGridView) findViewById(R.id.grid_test_group2); 37 | mGridView2.setGRID_TYPE(2); 38 | mGridView3 = (ImageGridView) findViewById(R.id.grid_test_group3); 39 | mGridView3.setGRID_TYPE(3); 40 | mSingleImageView = (SingleImageView) findViewById(R.id.avatar); 41 | mGridView.updateNetPhotos(createTestData()); 42 | } 43 | 44 | private ArrayList createTestData() { 45 | ArrayList result = new ArrayList<>(); 46 | result.add("http://img2.imgtn.bdimg.com/it/u=2042486160,1330339958&fm=200&gp=0.jpg"); 47 | result.add("http://img1.3lian.com/img13/c3/82/d/64.jpg"); 48 | result.add("http://img3.duitang.com/uploads/item/201601/23/20160123202447_kYyjz.jpeg"); 49 | result.add("http://img.ycwb.com/news/attachement/jpg/site2/20130328/90fba601558912bdd7bd4d.jpg"); 50 | result.add("http://h.hiphotos.baidu.com/zhidao/pic/item/5fdf8db1cb1349549e1cd9df534e9258d1094a0e.jpg"); 51 | result.add("http://duwanjuancn.qiniudn.com/wp-content/uploads/20141018/20141018185310259.jpg"); 52 | result.add("http://img.7160.com/uploads/allimg/160513/12-160513155949.jpg"); 53 | result.add("http://img2.imgtn.bdimg.com/it/u=1724555645,204198543&fm=27&gp=0.jpg"); 54 | return result; 55 | } 56 | 57 | @Override 58 | public void onImageClick(View clickImage, SquareImage squareImage) { 59 | 60 | } 61 | 62 | @Override 63 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 64 | super.onActivityResult(requestCode, resultCode, data); 65 | if (resultCode == RESULT_OK) { 66 | mGridView.onParentResult(requestCode, data); 67 | mGridView2.onParentResult(requestCode, data); 68 | mSingleImageView.onParentResult(requestCode, data); 69 | }else if (resultCode==3){ 70 | mGridView.onParentResult(requestCode, data); 71 | mGridView3.onParentResult(requestCode, data); 72 | mSingleImageView.onParentResult(requestCode, data); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/loopeer/android/apps/imagegroupview/TestIntentActivity.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.apps.imagegroupview; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | public class TestIntentActivity extends AppCompatActivity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | setContentView(R.layout.activity_test_intent); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_0.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_5.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_6.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/sample_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/drawable-xxhdpi/sample_7.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 23 | 24 | 28 | 29 | 37 | 38 | 39 | 40 | 50 | 51 | 65 | 66 | 67 | 76 | 77 | 94 | 95 | 104 | 105 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_test_intent.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #ab5510 5 | #44ab5510 6 | @color/color_D80C18 7 | 8 | #D80C18 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 250dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ImageGroupView 3 | 4 | Hello world! 5 | Settings 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.2.0' 5 | repositories { 6 | jcenter() 7 | google() 8 | mavenCentral() 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.0.1' 12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | 15 | // NOTE: Do not place your application dependencies here; they belong 16 | // in the individual module build.gradle files 17 | } 18 | } 19 | 20 | plugins { 21 | id "com.jfrog.bintray" version "1.7.3" 22 | } 23 | 24 | allprojects { 25 | repositories { 26 | jcenter() 27 | google() 28 | mavenCentral() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | target_sdk_version=26 2 | min_sdk_version=16 3 | build_tools_version=26.0.2 4 | compile_sdk_version=26 5 | version_code=1 6 | version_name=1.0.0 7 | 8 | support_version=26.0.2 9 | fresco_version=1.5.0 10 | #fresco_version=0.14.1 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Sep 18 11:19:07 CST 2017 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-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /imagegroupview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /imagegroupview/bintray.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.github.dcendents.android-maven' 2 | apply plugin: 'com.jfrog.bintray' 3 | 4 | version = '1.0.41' 5 | 6 | uploadArchives { 7 | repositories { 8 | mavenDeployer { 9 | repository(url: "file:///Users/todou/.m2/repository") 10 | } 11 | } 12 | } 13 | 14 | def siteUrl = 'https://github.com/loopeer/ImageGroupView' // 项目的主页 15 | def gitUrl = 'https://github.com/loopeer/ImageGroupView.git' // Git仓库的url 16 | group = "com.loopeer.lib" 17 | install { 18 | repositories.mavenInstaller { 19 | // This generates POM.xml with proper parameters 20 | pom { 21 | project { 22 | packaging 'aar' 23 | // Add your description here 24 | name 'ImageGroupView, you can show ic_image_default and add images by it. You can click the ' + 25 | 'ic_image_default to see the images by viewpager and it can also be scale. Last you can add photo easily' //项目描述 26 | url siteUrl 27 | // Set your license 28 | licenses { 29 | license { 30 | name 'The Apache Software License, Version 2.0' 31 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 32 | } 33 | } 34 | developers { 35 | developer { 36 | id 'loopeer' 37 | name 'loopeer' 38 | email 'loopeerteam@gmail.com' 39 | } 40 | } 41 | scm { 42 | connection gitUrl 43 | developerConnection gitUrl 44 | url siteUrl 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | task sourcesJar(type: Jar) { 52 | from android.sourceSets.main.java.srcDirs 53 | classifier = 'sources' 54 | } 55 | artifacts { 56 | archives sourcesJar 57 | } 58 | Properties properties = new Properties() 59 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 60 | bintray { 61 | user = properties.getProperty("bintray.user") 62 | key = properties.getProperty("bintray.apikey") 63 | configurations = ['archives'] 64 | pkg { 65 | repo = "maven" //发布到Bintray的那个仓库里,默认账户有四个库,我们这里上传到maven库 66 | name = "imagegroupview" //发布到Bintray上的项目名字 67 | websiteUrl = siteUrl 68 | vcsUrl = gitUrl 69 | licenses = ["Apache-2.0"] 70 | publish = true 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /imagegroupview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion Integer.parseInt(compile_sdk_version) 6 | buildToolsVersion build_tools_version 7 | 8 | defaultConfig { 9 | minSdkVersion min_sdk_version 10 | targetSdkVersion target_sdk_version 11 | versionCode Integer.parseInt(version_code) 12 | versionName version_name 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | lintOptions { 22 | abortOnError false 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | compile 'com.android.support:appcompat-v7:' + support_version 29 | compile 'com.android.support:recyclerview-v7:' + support_version 30 | compile 'com.facebook.fresco:fresco:' + fresco_version 31 | compile 'com.facebook.fresco:imagepipeline-okhttp:' + fresco_version 32 | compile 'com.android.support:support-core-utils:' + support_version 33 | compile 'com.yalantis:ucrop:2.2.0' 34 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 35 | } 36 | 37 | apply from: 'bintray.gradle' 38 | repositories { 39 | mavenCentral() 40 | google() 41 | } 42 | -------------------------------------------------------------------------------- /imagegroupview/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/todou/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /imagegroupview/src/androidTest/java/com/loopeer/android/apps/imagegroupview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.apps.imagegroupview; 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 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 17 | 18 | 22 | 23 | 27 | 28 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/OnImageClickListener.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview 2 | 3 | import android.view.View 4 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage 5 | 6 | 7 | interface OnImageClickListener { 8 | fun onImageClick(clickImage: View, squareImage: SquareImage) 9 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/OnTabOneClickListener.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview 2 | 3 | 4 | interface OnTabOneClickListener { 5 | fun onTabOneClick() 6 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/activity/AlbumActivity.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.activity 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.content.Intent 6 | import android.database.Cursor 7 | import android.os.AsyncTask 8 | import android.os.Bundle 9 | import android.provider.MediaStore 10 | import android.support.v4.app.ActivityCompat 11 | import android.support.v4.content.CursorLoader 12 | import android.support.v4.content.Loader 13 | import android.view.View 14 | import com.loopeer.android.librarys.imagegroupview.NavigatorImage 15 | import com.loopeer.android.librarys.imagegroupview.adapter.ImageAdapter 16 | import com.loopeer.android.librarys.imagegroupview.adapter.RecyclerViewAdapter 17 | import com.loopeer.android.librarys.imagegroupview.model.Image 18 | import com.loopeer.android.librarys.imagegroupview.model.ImageFolder 19 | import com.loopeer.android.librarys.imagegroupview.uimanager.IGRecycler 20 | import java.io.File 21 | import java.util.* 22 | 23 | 24 | class AlbumActivity : UIPatternActivity(), IGRecycler { 25 | private val DRAG_PHOTO = 3 26 | private var gtype: Int = 0 27 | 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | var intent = intent 31 | gtype = intent.getIntExtra("gtype", 0) 32 | } 33 | 34 | override fun adapterUpdateContentView(recyclerViewAdapter: RecyclerViewAdapter<*>, folder: ImageFolder?) { 35 | var mImageAdapter = (recyclerViewAdapter as ImageAdapter) 36 | mImageAdapter.setAlbumType(mAlbumType) 37 | mImageAdapter.setIsAvatarType(mIsAvatarType) 38 | mImageAdapter.updateFolderImageData(folder) 39 | } 40 | 41 | override fun adapterUpdateSelect(recyclerViewAdapter: RecyclerViewAdapter<*>, mSelectedImages: MutableList, position: Int) { 42 | (recyclerViewAdapter as ImageAdapter).updateSelectImages(mSelectedImages, position) 43 | } 44 | 45 | 46 | override fun createRecyclerViewAdapter(): RecyclerViewAdapter { 47 | val madapter = ImageAdapter(this) 48 | madapter.setOnImageClickListener(this) 49 | return madapter 50 | } 51 | 52 | @SuppressLint("StaticFieldLeak") 53 | override fun doParseData(data: Cursor) { 54 | 55 | object : AsyncTask>() { 56 | 57 | override fun doInBackground(vararg params: Cursor): MutableList { 58 | val data = params[0] 59 | if (data != null) { 60 | val folders = mutableListOf() 61 | val count = data.count 62 | if (count > 0) { 63 | data.moveToFirst() 64 | do { 65 | val path = data.getString(data.getColumnIndexOrThrow(NavigatorImage.IMAGE_PROJECTION[0])) 66 | val name = data.getString(data.getColumnIndexOrThrow(NavigatorImage.IMAGE_PROJECTION[1])) 67 | val dateTime = data.getLong(data.getColumnIndexOrThrow(NavigatorImage.IMAGE_PROJECTION[2])) 68 | val image = Image(path, name, dateTime) 69 | 70 | val imageFile = File(path) 71 | val folderFile = imageFile.parentFile 72 | val folder = ImageFolder() 73 | folder.name = folderFile.name 74 | folder.dir = folderFile.absolutePath 75 | folder.firstImagePath = path 76 | if (!folders.contains(folder)) { 77 | val imageList = ArrayList() 78 | imageList.add(image) 79 | folder.count++ 80 | folder.images = imageList 81 | folders.add(folder) 82 | } else { 83 | val f = folders.get(folders.indexOf(folder)) 84 | f.images.add(image) 85 | f.count++ 86 | } 87 | } while (data.moveToNext()) 88 | 89 | return folders 90 | } 91 | } 92 | 93 | return mutableListOf() 94 | } 95 | 96 | override fun onPostExecute(list: MutableList) { 97 | super.onPostExecute(list) 98 | getCustomPopupWindowView()?.updateFolderData(createFoldersWithAllImageFolder(list)) 99 | } 100 | }.execute(data) 101 | } 102 | 103 | override fun finishWithResult() { 104 | val intent = intent 105 | intent.putExtra(NavigatorImage.EXTRA_PHOTOS_URL, createUrls(mSelectedImages)) 106 | intent.putExtra(NavigatorImage.EXTRA_IMAGE_GROUP_ID, mImageGroupId) 107 | if (gtype == 3) setResult(3, intent) 108 | else setResult(Activity.RESULT_OK, intent) 109 | finish() 110 | } 111 | 112 | override fun onClick(v: View?) { 113 | if (gtype == 3) 114 | pickSelectImages() 115 | else { 116 | super.onClick(v) 117 | } 118 | } 119 | 120 | 121 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 122 | super.onActivityResult(requestCode, resultCode, data) 123 | if (data == null || resultCode != Activity.RESULT_OK && mAlbumType == TAKE_PHOTO) { 124 | this.finish() 125 | } 126 | if (data == null || resultCode != Activity.RESULT_OK) return 127 | 128 | when (requestCode) { 129 | DRAG_PHOTO -> 130 | finishWithResult() 131 | } 132 | } 133 | 134 | private fun pickSelectImages() { 135 | val intent = Intent(this, ImagePickerActivity::class.java) 136 | intent.putExtra(NavigatorImage.EXTRA_PHOTOS_URL, createUrls(mSelectedImages)) 137 | intent.putExtra(NavigatorImage.EXTRA_IMAGE_GROUP_ID, mImageGroupId) 138 | ActivityCompat.startActivityForResult(this@AlbumActivity, 139 | intent, NavigatorImage.RESULT_SELECT_PHOTO, 140 | null) 141 | } 142 | 143 | override fun onCreateLoader(id: Int, args: Bundle?): Loader { 144 | val cursorLoader = CursorLoader(this, 145 | MediaStore.Images.Media.EXTERNAL_CONTENT_URI, NavigatorImage.IMAGE_PROJECTION, null, null, NavigatorImage.IMAGE_PROJECTION[2] + " DESC") 146 | return cursorLoader 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/activity/ImagePickerActivity.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.activity; 2 | 3 | 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.support.v7.widget.helper.ItemTouchHelper; 11 | import android.util.Log; 12 | import android.view.Menu; 13 | import android.view.MenuItem; 14 | import android.view.View; 15 | import android.widget.TextView; 16 | 17 | import com.loopeer.android.librarys.imagegroupview.NavigatorImage; 18 | import com.loopeer.android.librarys.imagegroupview.R; 19 | import com.loopeer.android.librarys.imagegroupview.model.Image; 20 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 21 | import com.loopeer.android.librarys.imagegroupview.view.DragRecycleAdapter; 22 | import com.loopeer.android.librarys.imagegroupview.view.DragRecycleView; 23 | import com.loopeer.android.librarys.imagegroupview.view.SimpleItemTouchHelperCallback; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | public class ImagePickerActivity extends AppCompatActivity implements View.OnClickListener { 29 | 30 | 31 | List images; 32 | List preImages; 33 | public TextView tv; 34 | private MenuItem mSubmitMenu; 35 | private TextView mTextSubmit; 36 | private int mImageGroupId; 37 | DragRecycleAdapter adapter; 38 | 39 | @Override 40 | public void onCreate(@Nullable Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_image_picker); 43 | pareIntent(); 44 | initData(); 45 | initView(); 46 | } 47 | 48 | public void initData() { 49 | preImages = new ArrayList<>(); 50 | } 51 | 52 | private void initView() { 53 | DragRecycleView dragRecycleView = (DragRecycleView) findViewById(R.id.drag_view); 54 | tv = (TextView) findViewById(R.id.delete); 55 | dragRecycleView.setLayoutManager(new GridLayoutManager(ImagePickerActivity.this, 4)); 56 | dragRecycleView.setHasFixedSize(true); 57 | dragRecycleView.tv = tv; 58 | 59 | for (Image image : images) { 60 | SquareImage squareImage = new SquareImage(image.url, null, getPhotoKey(image.time), SquareImage.PhotoType.LOCAL); 61 | preImages.add(squareImage); 62 | } 63 | adapter = new DragRecycleAdapter(this, preImages); 64 | dragRecycleView.setAdapter(adapter); 65 | //创建SimpleItemTouchHelperCallback 66 | ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter); 67 | //用Callback构造ItemtouchHelper 68 | ItemTouchHelper touchHelper = new ItemTouchHelper(callback); 69 | //调用ItemTouchHelper的attachToRecyclerView方法建立联系 70 | touchHelper.attachToRecyclerView(dragRecycleView); 71 | } 72 | 73 | private void pareIntent() { 74 | Intent intent = this.getIntent(); 75 | images = (List) intent.getSerializableExtra(NavigatorImage.EXTRA_PHOTOS_URL); 76 | mImageGroupId = intent.getIntExtra(NavigatorImage.EXTRA_IMAGE_GROUP_ID, 0); 77 | } 78 | 79 | @NonNull 80 | private String getPhotoKey(long time) { 81 | return "image_" + time; 82 | } 83 | 84 | @Override 85 | public boolean onCreateOptionsMenu(Menu menu) { 86 | getMenuInflater().inflate(R.menu.menu_image_group_submit, menu); 87 | updateSubmitMenu(menu); 88 | return true; 89 | } 90 | 91 | private void updateSubmitMenu(Menu menuItem) { 92 | mSubmitMenu = menuItem.findItem(R.id.action_submit); 93 | View view = mSubmitMenu.getActionView(); 94 | mTextSubmit = (TextView) view.findViewById(R.id.text_image_submit); 95 | mTextSubmit.setOnClickListener(this); 96 | } 97 | 98 | @Override 99 | public boolean onOptionsItemSelected(MenuItem item) { 100 | int id = item.getItemId(); 101 | if (id == android.R.id.home) { 102 | finish(); 103 | return true; 104 | } 105 | return super.onOptionsItemSelected(item); 106 | } 107 | 108 | @Override 109 | public void onClick(View v) { 110 | Log.d("activityLog", "submit"); 111 | finishWithResult(); 112 | } 113 | 114 | private void finishWithResult() { 115 | ArrayList pics = new ArrayList<>(); 116 | for (SquareImage s : adapter.mData 117 | ) { 118 | Log.d("log ", "mdata " + s.localUrl); 119 | pics.add(s.localUrl); 120 | } 121 | Intent intent = getIntent(); 122 | intent.putExtra(NavigatorImage.EXTRA_PHOTOS_URL, pics); 123 | intent.putExtra(NavigatorImage.EXTRA_IMAGE_GROUP_ID, mImageGroupId); 124 | setResult(RESULT_OK, intent); 125 | finish(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/activity/ImageScaleActivity.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentTransaction; 7 | import android.support.v7.app.AppCompatActivity; 8 | 9 | import com.loopeer.android.librarys.imagegroupview.NavigatorImage; 10 | import com.loopeer.android.librarys.imagegroupview.OnTabOneClickListener; 11 | import com.loopeer.android.librarys.imagegroupview.R; 12 | import com.loopeer.android.librarys.imagegroupview.fragment.ScaleImageFragment; 13 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 14 | 15 | public class ImageScaleActivity extends AppCompatActivity implements OnTabOneClickListener { 16 | 17 | private String url; 18 | private int placeholderDrawable; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_scale_image); 24 | 25 | pareIntent(); 26 | setFragment(); 27 | } 28 | 29 | private void pareIntent() { 30 | Intent intent = getIntent(); 31 | url = intent.getStringExtra(NavigatorImage.EXTRA_IMAGE_URL); 32 | placeholderDrawable = intent.getIntExtra(NavigatorImage.EXTRA_IMAGE_PLACE_DRAWABLE_ID, R.drawable.ic_image_default); 33 | } 34 | 35 | private void setFragment() { 36 | FragmentManager fragmentManager = getSupportFragmentManager(); 37 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 38 | ScaleImageFragment scaleImageFragment = ScaleImageFragment.newInstance(new SquareImage(null, url, null, SquareImage.PhotoType.NETWORK), placeholderDrawable); 39 | scaleImageFragment.setOneTabListener(this); 40 | fragmentTransaction.add(R.id.container, scaleImageFragment).commit(); 41 | } 42 | 43 | @Override 44 | public void onTabOneClick() { 45 | this.finish(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/activity/UserCameraActivity.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.ContentValues; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.provider.MediaStore; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.text.TextUtils; 11 | import android.util.Log; 12 | 13 | import com.loopeer.android.librarys.imagegroupview.NavigatorImage; 14 | import com.loopeer.android.librarys.imagegroupview.utils.FileUtils; 15 | import com.loopeer.android.librarys.imagegroupview.utils.ImageGroupUtils; 16 | 17 | import java.io.File; 18 | 19 | public class UserCameraActivity extends AppCompatActivity { 20 | 21 | private String photoUrl; 22 | private final String EXTRA_PHOTO_URL = NavigatorImage.EXTRA_PHOTO_URL; 23 | 24 | 25 | private final int RSULT_IMAGE_CAPTURE = 2002; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | if (savedInstanceState != null) { 31 | photoUrl = savedInstanceState.getString(EXTRA_PHOTO_URL); 32 | if (!TextUtils.isEmpty(photoUrl)) 33 | recoverFile(photoUrl); 34 | } 35 | 36 | if (savedInstanceState == null) { 37 | showCamera(); 38 | } 39 | } 40 | 41 | private void recoverFile(String url) { 42 | String path = ImageGroupUtils.getPathOfPhotoByUri(this, Uri.parse(url)); 43 | try { 44 | if (!TextUtils.isEmpty(path) && FileUtils.fileIsAvaliableImage(new File(path))) { 45 | finishWithResult(url); 46 | } else { 47 | finishAfterDelete(url); 48 | } 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | 54 | protected void onSaveInstanceState(Bundle outState) { 55 | super.onSaveInstanceState(outState); 56 | outState.putString(EXTRA_PHOTO_URL, photoUrl); 57 | } 58 | 59 | @Override 60 | public void onActivityResult(int requestCode, int resultCode, Intent intent) { 61 | if (RSULT_IMAGE_CAPTURE == requestCode && resultCode == Activity.RESULT_OK) { 62 | finishWithResult(photoUrl); 63 | } else { 64 | finishAfterDelete(photoUrl); 65 | } 66 | } 67 | 68 | private void finishAfterDelete(String url) { 69 | String path = ImageGroupUtils.getPathOfPhotoByUri(this, Uri.parse(url)); 70 | if (!TextUtils.isEmpty(path)) 71 | FileUtils.deleteFile(new File(path)); 72 | finish(); 73 | } 74 | 75 | private void finishWithResult(String url) { 76 | Intent rsl = new Intent(); 77 | rsl.putExtra(EXTRA_PHOTO_URL, ImageGroupUtils.getPathOfPhotoByUri(this, Uri.parse(url))); 78 | setResult(Activity.RESULT_OK, rsl); 79 | finish(); 80 | } 81 | 82 | private void showCamera() { 83 | Intent intent1 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 84 | ContentValues values = new ContentValues(); 85 | Uri photoUri = getContentResolver() 86 | .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); 87 | photoUrl = photoUri.toString(); 88 | intent1.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); 89 | startActivityForResult(intent1, RSULT_IMAGE_CAPTURE); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/adapter/AlbumRecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.content.ContextCompat; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.facebook.drawee.view.SimpleDraweeView; 12 | import com.loopeer.android.librarys.imagegroupview.R; 13 | import com.loopeer.android.librarys.imagegroupview.model.ImageFolder; 14 | import com.loopeer.android.librarys.imagegroupview.utils.ImageDisplayHelper; 15 | 16 | import java.util.List; 17 | 18 | public class AlbumRecyclerAdapter extends RecyclerViewAdapter { 19 | 20 | private ImageFolder mSelectFolder; 21 | 22 | public interface OnItemClickListener { 23 | void onItemClick(ImageFolder imageFolder); 24 | } 25 | 26 | private OnItemClickListener mOnItemClickListener; 27 | 28 | public AlbumRecyclerAdapter(Context context) { 29 | super(context); 30 | } 31 | 32 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 33 | mOnItemClickListener = onItemClickListener; 34 | } 35 | 36 | @Override 37 | public void updateData(List data) { 38 | mSelectFolder = data.get(0); 39 | super.updateData(data); 40 | } 41 | 42 | @Override 43 | public void bindView(final ImageFolder var1, int var2, RecyclerView.ViewHolder var3, List payloads) { 44 | if (var3 instanceof AlbumViewHolder) { 45 | AlbumViewHolder albumViewHolder = (AlbumViewHolder) var3; 46 | albumViewHolder.bind(var1); 47 | albumViewHolder.itemView.setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | onFolderSelected(var1); 51 | } 52 | }); 53 | albumViewHolder.setFolderSelected(var1.equals(mSelectFolder)); 54 | } 55 | } 56 | 57 | private void onFolderSelected(ImageFolder var1) { 58 | mSelectFolder = var1; 59 | mOnItemClickListener.onItemClick(var1); 60 | notifyDataSetChanged(); 61 | } 62 | 63 | @Override 64 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 65 | View view = getLayoutInflater().inflate(R.layout.list_item_album, parent, false); 66 | return new AlbumViewHolder(view); 67 | } 68 | 69 | static class AlbumViewHolder extends RecyclerView.ViewHolder { 70 | 71 | private SimpleDraweeView mImage; 72 | private TextView mTextAlbumName; 73 | private TextView mTextSize; 74 | private ImageView mSelectedIndicator; 75 | 76 | public AlbumViewHolder(View itemView) { 77 | super(itemView); 78 | 79 | mImage = (SimpleDraweeView) itemView.findViewById(R.id.image_album); 80 | mTextAlbumName = (TextView) itemView.findViewById(R.id.text_album_name); 81 | mTextSize = (TextView) itemView.findViewById(R.id.text_album_size); 82 | mSelectedIndicator = (ImageView) itemView.findViewById(R.id.image_album_selected_indicator); 83 | mSelectedIndicator.setColorFilter(ContextCompat.getColor(itemView.getContext(), R.color.image_group_widget)); 84 | } 85 | 86 | public void bind(ImageFolder imageFolder) { 87 | ImageDisplayHelper.displayImageLocal(mImage, imageFolder.firstImagePath, 200, 200); 88 | mTextAlbumName.setText(imageFolder.name); 89 | mTextSize.setText(Integer.toString(imageFolder.count)); 90 | } 91 | 92 | public void setFolderSelected(boolean equals) { 93 | mSelectedIndicator.setVisibility(equals ? View.VISIBLE : View.GONE); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/adapter/ImagesSwitcherAdapter.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.view.PagerAdapter; 6 | import android.view.ViewGroup; 7 | 8 | import com.loopeer.android.librarys.imagegroupview.OnTabOneClickListener; 9 | import com.loopeer.android.librarys.imagegroupview.fragment.ScaleImageFragment; 10 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 11 | import com.loopeer.android.librarys.imagegroupview.view.CustomFragmentPagerAdapter; 12 | 13 | import java.util.ArrayList; 14 | 15 | public class ImagesSwitcherAdapter extends CustomFragmentPagerAdapter { 16 | 17 | private ArrayList images; 18 | private OnTabOneClickListener onTabOneClickListener; 19 | private int placeholderDrawable; 20 | private FragmentManager mFragmentManager; 21 | 22 | public ImagesSwitcherAdapter(FragmentManager fm, int placeholderDrawable) { 23 | super(fm); 24 | mFragmentManager = fm; 25 | this.placeholderDrawable = placeholderDrawable; 26 | images = new ArrayList<>(); 27 | } 28 | 29 | public ScaleImageFragment getFragmentByPosition(int position) { 30 | return (ScaleImageFragment) mFragmentManager.findFragmentByTag(makeFragmentName(position)); 31 | } 32 | 33 | public void setOnTabOneClickListener(OnTabOneClickListener onTabOneClickListener) { 34 | this.onTabOneClickListener = onTabOneClickListener; 35 | } 36 | 37 | public void setImages(ArrayList strings) { 38 | images.clear(); 39 | images.addAll(strings); 40 | notifyDataSetChanged(); 41 | } 42 | 43 | @Override 44 | public Fragment getItem(int position) { 45 | ScaleImageFragment scaleImageFragment = ScaleImageFragment.newInstance(images.get(position), placeholderDrawable); 46 | scaleImageFragment.setOneTabListener(onTabOneClickListener); 47 | return scaleImageFragment; 48 | } 49 | 50 | @Override 51 | public Object instantiateItem(ViewGroup container, int position) { 52 | ScaleImageFragment scaleImageFragment = (ScaleImageFragment) super.instantiateItem(container, position); 53 | scaleImageFragment.setSquareImage(images.get(position)); 54 | return scaleImageFragment; 55 | } 56 | 57 | @Override 58 | public int getCount() { 59 | return images.size(); 60 | } 61 | 62 | @Override 63 | public int getItemPosition(Object object) { 64 | return PagerAdapter.POSITION_NONE; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/adapter/RecyclerViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public abstract class RecyclerViewAdapter extends RecyclerView.Adapter { 11 | private final Context mContext; 12 | private final LayoutInflater mInflater; 13 | private List mData; 14 | 15 | public RecyclerViewAdapter(Context context) { 16 | this.mContext = context; 17 | this.mInflater = LayoutInflater.from(context); 18 | this.mData = new ArrayList<>(); 19 | } 20 | 21 | public void updateData(List data) { 22 | this.setData(data); 23 | this.notifyDataSetChanged(); 24 | } 25 | 26 | public void setData(List data) { 27 | this.mData.clear(); 28 | if (data != null) { 29 | this.mData.addAll(data); 30 | } 31 | 32 | } 33 | 34 | public LayoutInflater getLayoutInflater() { 35 | return this.mInflater; 36 | } 37 | 38 | public Context getContext() { 39 | return this.mContext; 40 | } 41 | 42 | @Override 43 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 44 | 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads) { 49 | T data = this.getItem(position); 50 | this.bindView(data, position, holder, payloads); 51 | } 52 | 53 | 54 | public abstract void bindView(T var1, int var2, RecyclerView.ViewHolder var3, List payloads); 55 | 56 | public T getItem(int position) { 57 | return this.mData.get(position); 58 | } 59 | 60 | public int getItemCount() { 61 | return this.mData == null ? 0 : this.mData.size(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/fragment/GetImageDialogFragment.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by YuGang Yang on September 05, 2014. 3 | * Copyright 2007-2015 Loopeer.com. All rights reserved. 4 | */ 5 | package com.loopeer.android.librarys.imagegroupview.fragment; 6 | 7 | import android.app.AlertDialog; 8 | import android.app.Dialog; 9 | import android.content.Context; 10 | import android.os.Bundle; 11 | import android.support.annotation.NonNull; 12 | import android.support.v4.app.DialogFragment; 13 | import android.support.v4.app.FragmentManager; 14 | import android.view.LayoutInflater; 15 | import android.view.View; 16 | 17 | import com.loopeer.android.librarys.imagegroupview.R; 18 | 19 | public class GetImageDialogFragment extends DialogFragment implements View.OnClickListener { 20 | 21 | public interface ClickListener { 22 | void click(); 23 | } 24 | 25 | private ClickListener mPositiveListener; 26 | private ClickListener mNegativeListener; 27 | 28 | public static GetImageDialogFragment newInstance() { 29 | GetImageDialogFragment getImageDialogFragment = new GetImageDialogFragment(); 30 | return getImageDialogFragment; 31 | } 32 | 33 | @NonNull 34 | @Override 35 | public Dialog onCreateDialog(Bundle savedInstanceState) { 36 | AlertDialog.Builder builder; 37 | 38 | LayoutInflater inflater = 39 | (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 40 | final View layout = inflater.inflate(R.layout.dialog_fragment_get_photo, null); 41 | 42 | layout.findViewById(android.R.id.button1).setOnClickListener(this); 43 | layout.findViewById(android.R.id.button2).setOnClickListener(this); 44 | 45 | builder = new AlertDialog.Builder(getActivity()); 46 | builder.setView(layout); 47 | return builder.create(); 48 | } 49 | 50 | @Override 51 | public void onClick(View view) { 52 | switch (view.getId()) { 53 | case android.R.id.button1: 54 | mNegativeListener.click(); 55 | break; 56 | case android.R.id.button2: 57 | mPositiveListener.click(); 58 | break; 59 | 60 | } 61 | dismiss(); 62 | } 63 | 64 | 65 | public static class Builder { 66 | GetImageDialogFragment getImageDialogFragment; 67 | private FragmentManager mManager; 68 | 69 | 70 | public Builder(FragmentManager manager) { 71 | getImageDialogFragment = GetImageDialogFragment.newInstance(); 72 | mManager = manager; 73 | } 74 | 75 | public Builder setPositiveListener(ClickListener clickListener) { 76 | getImageDialogFragment.mPositiveListener = clickListener; 77 | return this; 78 | } 79 | 80 | public Builder setNegativeListener(ClickListener clickListener) { 81 | getImageDialogFragment.mNegativeListener = clickListener; 82 | return this; 83 | } 84 | 85 | public void show() { 86 | getImageDialogFragment.show(mManager, ""); 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/model/Image.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Image implements Serializable { 6 | 7 | public String url; 8 | public String name; 9 | public long time; 10 | 11 | public Image(String path, String name, long time){ 12 | this.url = path; 13 | this.name = name; 14 | this.time = time; 15 | } 16 | 17 | public Image(String photoTakeurl) { 18 | url = photoTakeurl; 19 | } 20 | 21 | @Override 22 | public boolean equals(Object o) { 23 | if (this == o) return true; 24 | if (o == null || getClass() != o.getClass()) return false; 25 | 26 | Image image = (Image) o; 27 | 28 | if (url != null ? !url.equals(image.url) : image.url != null) return false; 29 | return !(name != null ? !name.equals(image.name) : image.name != null); 30 | 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | int result = url != null ? url.hashCode() : 0; 36 | result = 31 * result + (name != null ? name.hashCode() : 0); 37 | return result; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/model/ImageFolder.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | public class ImageFolder implements Serializable { 8 | 9 | public String dir; 10 | public String firstImagePath; 11 | public String name; 12 | public int count; 13 | public List images; 14 | 15 | public ImageFolder() { 16 | images = new ArrayList(); 17 | } 18 | 19 | @Override 20 | public boolean equals(Object o) { 21 | if (this == o) return true; 22 | if (o == null || getClass() != o.getClass()) return false; 23 | 24 | ImageFolder that = (ImageFolder) o; 25 | 26 | if (dir != null ? !dir.equals(that.dir) : that.dir != null) return false; 27 | return !(name != null ? !name.equals(that.name) : that.name != null); 28 | 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | int result = dir != null ? dir.hashCode() : 0; 34 | result = 31 * result + (name != null ? name.hashCode() : 0); 35 | return result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/model/ImageSwitcherWrapper.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.model; 2 | 3 | public class ImageSwitcherWrapper { 4 | 5 | public SquareImage squareImage; 6 | public int originPosition; 7 | 8 | public ImageSwitcherWrapper(SquareImage squareImage, int originPosition) { 9 | this.squareImage = squareImage; 10 | this.originPosition = originPosition; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/model/SquareImage.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.model; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class SquareImage implements Parcelable { 10 | 11 | public int id; 12 | public String localUrl; 13 | public String interNetUrl; 14 | public String urlKey; 15 | public PhotoType type; 16 | public int left, top, width, height; 17 | 18 | public SquareImage() { 19 | } 20 | 21 | public float getCenterX() { 22 | return left + (float) width / 2; 23 | } 24 | 25 | public float getCenterY() { 26 | return top + (float) height / 2; 27 | } 28 | 29 | public SquareImage(String localUrl, String interNetUrl, String urlKey, PhotoType type) { 30 | this.localUrl = localUrl; 31 | this.interNetUrl = interNetUrl; 32 | this.urlKey = urlKey; 33 | this.type = type; 34 | } 35 | 36 | public void setPosition(int left, int top, int width, int height) { 37 | this.left = left; 38 | this.top = top; 39 | this.width = width; 40 | this.height = height; 41 | } 42 | 43 | public void setId(int id) { 44 | this.id = id; 45 | } 46 | 47 | protected SquareImage(Parcel in) { 48 | id = in.readInt(); 49 | localUrl = in.readString(); 50 | interNetUrl = in.readString(); 51 | urlKey = in.readString(); 52 | type = in.readParcelable(PhotoType.class.getClassLoader()); 53 | left = in.readInt(); 54 | top = in.readInt(); 55 | width = in.readInt(); 56 | height = in.readInt(); 57 | } 58 | 59 | @Override 60 | public void writeToParcel(Parcel dest, int flags) { 61 | dest.writeInt(id); 62 | dest.writeString(localUrl); 63 | dest.writeString(interNetUrl); 64 | dest.writeString(urlKey); 65 | dest.writeParcelable(type, flags); 66 | dest.writeInt(left); 67 | dest.writeInt(top); 68 | dest.writeInt(width); 69 | dest.writeInt(height); 70 | } 71 | 72 | public static final Creator CREATOR = new Creator() { 73 | @Override 74 | public SquareImage createFromParcel(Parcel in) { 75 | return new SquareImage(in); 76 | } 77 | 78 | @Override 79 | public SquareImage[] newArray(int size) { 80 | return new SquareImage[size]; 81 | } 82 | }; 83 | 84 | @Override 85 | public int describeContents() { 86 | return 0; 87 | } 88 | 89 | public enum PhotoType implements Parcelable { 90 | 91 | NETWORK("0"), 92 | 93 | LOCAL("1"); 94 | 95 | 96 | private String mValue; 97 | 98 | PhotoType(String value) { 99 | mValue = value; 100 | } 101 | 102 | @Override 103 | public String toString() { 104 | return mValue; 105 | } 106 | 107 | private static final Map 108 | STRING_MAPPING = new HashMap<>(); 109 | 110 | static { 111 | for (PhotoType commentType : PhotoType.values()) { 112 | STRING_MAPPING.put(commentType.toString().toUpperCase(), commentType); 113 | } 114 | } 115 | 116 | @SuppressWarnings("unused") 117 | public static PhotoType fromValue(String value) { 118 | return STRING_MAPPING.get(value.toUpperCase()); 119 | } 120 | 121 | public static final Creator CREATOR = new Creator() { 122 | 123 | public PhotoType createFromParcel(Parcel in) { 124 | PhotoType option = PhotoType.values()[in.readInt()]; 125 | option.mValue = in.readString(); 126 | return option; 127 | } 128 | 129 | public PhotoType[] newArray(int size) { 130 | return new PhotoType[size]; 131 | } 132 | 133 | }; 134 | 135 | @Override 136 | public int describeContents() { 137 | return 0; 138 | } 139 | 140 | @Override 141 | public void writeToParcel(Parcel out, int flags) { 142 | out.writeInt(ordinal()); 143 | out.writeString(mValue); 144 | } 145 | } 146 | 147 | @Override 148 | public boolean equals(Object o) { 149 | if (this == o) return true; 150 | if (o == null || getClass() != o.getClass()) return false; 151 | 152 | SquareImage that = (SquareImage) o; 153 | 154 | if (id != that.id) return false; 155 | if (localUrl != null ? !localUrl.equals(that.localUrl) : that.localUrl != null) 156 | return false; 157 | if (interNetUrl != null ? !interNetUrl.equals(that.interNetUrl) : that.interNetUrl != null) 158 | return false; 159 | if (urlKey != null ? !urlKey.equals(that.urlKey) : that.urlKey != null) return false; 160 | return type == that.type; 161 | 162 | } 163 | 164 | @Override 165 | public int hashCode() { 166 | int result = id; 167 | result = 31 * result + (localUrl != null ? localUrl.hashCode() : 0); 168 | result = 31 * result + (interNetUrl != null ? interNetUrl.hashCode() : 0); 169 | result = 31 * result + (urlKey != null ? urlKey.hashCode() : 0); 170 | result = 31 * result + type.hashCode(); 171 | return result; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/photodraweeview/DefaultOnDoubleTapListener.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.photodraweeview; 2 | 3 | import android.graphics.RectF; 4 | import android.view.GestureDetector; 5 | import android.view.MotionEvent; 6 | 7 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 8 | import com.facebook.drawee.view.DraweeView; 9 | 10 | public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener { 11 | 12 | private Attacher mAttacher; 13 | 14 | public DefaultOnDoubleTapListener(Attacher attacher) { 15 | setPhotoDraweeViewAttacher(attacher); 16 | } 17 | 18 | @Override 19 | public boolean onSingleTapConfirmed(MotionEvent e) { 20 | 21 | if (mAttacher == null) { 22 | return false; 23 | } 24 | DraweeView draweeView = mAttacher.getDraweeView(); 25 | if (draweeView == null || draweeView.getTranslationX() != 0.0f || draweeView.getScaleX() != 1.0f) { 26 | return false; 27 | } 28 | 29 | if (mAttacher.getOnPhotoTapListener() != null) { 30 | final RectF displayRect = mAttacher.getDisplayRect(); 31 | 32 | if (null != displayRect) { 33 | final float x = e.getX(), y = e.getY(); 34 | if (displayRect.contains(x, y)) { 35 | float xResult = (x - displayRect.left) / displayRect.width(); 36 | float yResult = (y - displayRect.top) / displayRect.height(); 37 | mAttacher.getOnPhotoTapListener().onPhotoTap(draweeView, xResult, yResult); 38 | return true; 39 | } 40 | } 41 | } 42 | 43 | if (mAttacher.getOnViewTapListener() != null) { 44 | mAttacher.getOnViewTapListener().onViewTap(draweeView, e.getX(), e.getY()); 45 | return true; 46 | } 47 | 48 | return false; 49 | } 50 | 51 | @Override 52 | public boolean onDoubleTap(MotionEvent event) { 53 | if (mAttacher == null) { 54 | return false; 55 | } 56 | 57 | try { 58 | float scale = mAttacher.getScale(); 59 | float x = event.getX(); 60 | float y = event.getY(); 61 | 62 | if (scale < mAttacher.getMediumScale()) { 63 | mAttacher.setScale(mAttacher.getMediumScale(), x, y, true); 64 | } else if (scale >= mAttacher.getMediumScale() && scale < mAttacher.getMaximumScale()) { 65 | mAttacher.setScale(mAttacher.getMaximumScale(), x, y, true); 66 | } else { 67 | mAttacher.setScale(mAttacher.getMinimumScale(), x, y, true); 68 | } 69 | } catch (Exception e) { 70 | // Can sometimes happen when getX() and getY() is called 71 | } 72 | return true; 73 | } 74 | 75 | @Override 76 | public boolean onDoubleTapEvent(MotionEvent event) { 77 | return false; 78 | } 79 | 80 | public void setPhotoDraweeViewAttacher(Attacher attacher) { 81 | mAttacher = attacher; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/photodraweeview/IAttacher.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.photodraweeview; 2 | 3 | import android.view.GestureDetector; 4 | import android.view.View; 5 | 6 | /** 7 | * **************************************************************************** 8 | * Copyright 2011, 2012 Chris Banes. 9 | * 10 | * Licensed under the Apache License, Version 2.0 (the "License"); 11 | * you may not use this file except in compliance with the License. 12 | * You may obtain a copy of the License at 13 | * 14 | * http://www.apache.org/licenses/LICENSE-2.0 15 | * 16 | * Unless required by applicable law or agreed to in writing, software 17 | * distributed under the License is distributed on an "AS IS" BASIS, 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | * See the License for the specific language governing permissions and 20 | * limitations under the License. 21 | * ***************************************************************************** 22 | */ 23 | 24 | public interface IAttacher { 25 | 26 | public static final float DEFAULT_MAX_SCALE = 3.0f; 27 | public static final float DEFAULT_MID_SCALE = 1.75f; 28 | public static final float DEFAULT_MIN_SCALE = 1.0f; 29 | public static final long ZOOM_DURATION = 200L; 30 | 31 | float getMinimumScale(); 32 | 33 | float getMediumScale(); 34 | 35 | float getMaximumScale(); 36 | 37 | void setMaximumScale(float maximumScale); 38 | 39 | void setMediumScale(float mediumScale); 40 | 41 | void setMinimumScale(float minimumScale); 42 | 43 | float getScale(); 44 | 45 | void setScale(float scale); 46 | 47 | void setScale(float scale, boolean animate); 48 | 49 | void setScale(float scale, float focalX, float focalY, boolean animate); 50 | 51 | void setZoomTransitionDuration(long duration); 52 | 53 | void setAllowParentInterceptOnEdge(boolean allow); 54 | 55 | void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener listener); 56 | 57 | void setOnScaleChangeListener(OnScaleChangeListener listener); 58 | 59 | void setOnLongClickListener(View.OnLongClickListener listener); 60 | 61 | void setOnPhotoTapListener(OnPhotoTapListener listener); 62 | 63 | void setOnViewTapListener(OnViewTapListener listener); 64 | 65 | OnPhotoTapListener getOnPhotoTapListener(); 66 | 67 | OnViewTapListener getOnViewTapListener(); 68 | 69 | void update(int imageInfoWidth, int imageInfoHeight); 70 | } 71 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/photodraweeview/OnPhotoTapListener.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.photodraweeview; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Interface definition for a callback to be invoked when the Photo is tapped with a single 7 | * tap. 8 | * 9 | * @author Chris Banes 10 | */ 11 | public interface OnPhotoTapListener { 12 | 13 | /** 14 | * A callback to receive where the user taps on a photo. You will only receive a callback if 15 | * the user taps on the actual photo, tapping on 'whitespace' will be ignored. 16 | * 17 | * @param view - View the user tapped. 18 | * @param x - where the user tapped from the of the Drawable, as percentage of the 19 | * Drawable width. 20 | * @param y - where the user tapped from the top of the Drawable, as percentage of the 21 | * Drawable height. 22 | */ 23 | void onPhotoTap(View view, float x, float y); 24 | } 25 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/photodraweeview/OnScaleChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.photodraweeview; 2 | 3 | /** 4 | * Interface definition for callback to be invoked when attached ImageView scale changes 5 | * 6 | * @author Marek Sebera 7 | */ 8 | public interface OnScaleChangeListener { 9 | /** 10 | * Callback for when the scale changes 11 | * 12 | * @param scaleFactor the scale factor (<1 for zoom out, >1 for zoom in) 13 | * @param focusX focal point X position 14 | * @param focusY focal point Y position 15 | */ 16 | void onScaleChange(float scaleFactor, float focusX, float focusY); 17 | } 18 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/photodraweeview/OnScaleDragGestureListener.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.photodraweeview; 2 | 3 | /** 4 | * **************************************************************************** 5 | * Copyright 2011, 2012 Chris Banes. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ***************************************************************************** 19 | */ 20 | 21 | public interface OnScaleDragGestureListener { 22 | void onDrag(float dx, float dy); 23 | 24 | void onFling(float startX, float startY, float velocityX, float velocityY); 25 | 26 | void onScale(float scaleFactor, float focusX, float focusY); 27 | 28 | void onScaleEnd(); 29 | } 30 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/photodraweeview/OnViewTapListener.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.photodraweeview; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Interface definition for a callback to be invoked when the ImageView is tapped with a single 7 | * tap. 8 | * 9 | * @author Chris Banes 10 | */ 11 | public interface OnViewTapListener { 12 | /** 13 | * A callback to receive where the user taps on a ImageView. You will receive a callback if 14 | * the user taps anywhere on the view, tapping on 'whitespace' will not be ignored. 15 | * 16 | * @param view - View the user tapped. 17 | * @param x - where the user tapped from the left of the View. 18 | * @param y - where the user tapped from the top of the View. 19 | */ 20 | void onViewTap(View view, float x, float y); 21 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/photodraweeview/PhotoDraweeView.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.photodraweeview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Matrix; 6 | import android.support.annotation.NonNull; 7 | import android.util.AttributeSet; 8 | import android.view.GestureDetector; 9 | import android.view.MotionEvent; 10 | 11 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 12 | import com.facebook.drawee.view.SimpleDraweeView; 13 | import com.loopeer.android.librarys.imagegroupview.utils.DisplayUtils; 14 | 15 | public class PhotoDraweeView extends SimpleDraweeView implements IAttacher { 16 | 17 | private Attacher mAttacher; 18 | private float mImageHeight; 19 | private float mImageWidth; 20 | private float mCenterX; 21 | private float mCenterY; 22 | 23 | private Matrix mMatrix; 24 | 25 | public PhotoDraweeView(Context context, GenericDraweeHierarchy hierarchy) { 26 | super(context, hierarchy); 27 | init(); 28 | } 29 | 30 | public PhotoDraweeView(Context context) { 31 | super(context); 32 | init(); 33 | } 34 | 35 | public PhotoDraweeView(Context context, AttributeSet attrs) { 36 | super(context, attrs); 37 | init(); 38 | } 39 | 40 | public PhotoDraweeView(Context context, AttributeSet attrs, int defStyle) { 41 | super(context, attrs, defStyle); 42 | init(); 43 | } 44 | 45 | protected void init() { 46 | if (mAttacher == null || mAttacher.getDraweeView() == null) { 47 | mAttacher = new Attacher(this); 48 | } 49 | initImageSize(); 50 | mMatrix = new Matrix(); 51 | } 52 | 53 | private void initImageSize() { 54 | mImageWidth = DisplayUtils.getScreenWidth(getContext()); 55 | mImageHeight = DisplayUtils.getScreenHeight(getContext()) - DisplayUtils.getStatusBarHeight(getContext()); 56 | mCenterX = mImageWidth / 2; 57 | mCenterY = mImageHeight / 2; 58 | } 59 | 60 | public void setImageHeight(float height) { 61 | mImageHeight = height; 62 | } 63 | 64 | public float getImageHeight() { 65 | return mImageHeight; 66 | } 67 | 68 | public float getImageWidth() { 69 | return mImageWidth; 70 | } 71 | 72 | public float getCenterX() { 73 | return mCenterX; 74 | } 75 | 76 | public float getCenterY() { 77 | return mCenterY; 78 | } 79 | 80 | @Override 81 | public boolean onTouchEvent(MotionEvent event) { 82 | 83 | return super.onTouchEvent(event); 84 | } 85 | 86 | @Override 87 | protected void onDraw(@NonNull Canvas canvas) { 88 | canvas.concat(mMatrix); 89 | int saveCount = canvas.save(); 90 | canvas.concat(mAttacher.getDrawMatrix()); 91 | super.onDraw(canvas); 92 | canvas.restoreToCount(saveCount); 93 | } 94 | 95 | @Override 96 | protected void onAttachedToWindow() { 97 | init(); 98 | super.onAttachedToWindow(); 99 | } 100 | 101 | @Override 102 | protected void onDetachedFromWindow() { 103 | mAttacher.onDetachedFromWindow(); 104 | super.onDetachedFromWindow(); 105 | } 106 | 107 | @Override 108 | public float getMinimumScale() { 109 | return mAttacher.getMinimumScale(); 110 | } 111 | 112 | @Override 113 | public float getMediumScale() { 114 | return mAttacher.getMediumScale(); 115 | } 116 | 117 | @Override 118 | public float getMaximumScale() { 119 | return mAttacher.getMaximumScale(); 120 | } 121 | 122 | @Override 123 | public void setMinimumScale(float minimumScale) { 124 | mAttacher.setMinimumScale(minimumScale); 125 | } 126 | 127 | @Override 128 | public void setMediumScale(float mediumScale) { 129 | mAttacher.setMediumScale(mediumScale); 130 | } 131 | 132 | @Override 133 | public void setMaximumScale(float maximumScale) { 134 | mAttacher.setMaximumScale(maximumScale); 135 | } 136 | 137 | @Override 138 | public float getScale() { 139 | return mAttacher.getScale(); 140 | } 141 | 142 | @Override 143 | public void setScale(float scale) { 144 | mAttacher.setScale(scale); 145 | } 146 | 147 | @Override 148 | public void setScale(float scale, boolean animate) { 149 | mAttacher.setScale(scale, animate); 150 | } 151 | 152 | @Override 153 | public void setScale(float scale, float focalX, float focalY, boolean animate) { 154 | mAttacher.setScale(scale, focalX, focalY, animate); 155 | } 156 | 157 | 158 | public void setScale(float scalex,float scaley) { 159 | mMatrix.setScale(1+scalex, 1 + scaley, getMeasuredWidth() / 2, getMeasuredWidth() / 2); 160 | invalidate(); 161 | } 162 | 163 | @Override 164 | public void setZoomTransitionDuration(long duration) { 165 | mAttacher.setZoomTransitionDuration(duration); 166 | } 167 | 168 | @Override 169 | public void setAllowParentInterceptOnEdge(boolean allow) { 170 | mAttacher.setAllowParentInterceptOnEdge(allow); 171 | } 172 | 173 | @Override 174 | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener listener) { 175 | mAttacher.setOnDoubleTapListener(listener); 176 | } 177 | 178 | @Override 179 | public void setOnScaleChangeListener(OnScaleChangeListener listener) { 180 | mAttacher.setOnScaleChangeListener(listener); 181 | } 182 | 183 | @Override 184 | public void setOnLongClickListener(OnLongClickListener listener) { 185 | mAttacher.setOnLongClickListener(listener); 186 | } 187 | 188 | @Override 189 | public void setOnPhotoTapListener(OnPhotoTapListener listener) { 190 | mAttacher.setOnPhotoTapListener(listener); 191 | } 192 | 193 | @Override 194 | public void setOnViewTapListener(OnViewTapListener listener) { 195 | mAttacher.setOnViewTapListener(listener); 196 | } 197 | 198 | @Override 199 | public OnPhotoTapListener getOnPhotoTapListener() { 200 | return mAttacher.getOnPhotoTapListener(); 201 | } 202 | 203 | @Override 204 | public OnViewTapListener getOnViewTapListener() { 205 | return mAttacher.getOnViewTapListener(); 206 | } 207 | 208 | @Override 209 | public void update(int imageInfoWidth, int imageInfoHeight) { 210 | mAttacher.update(imageInfoWidth, imageInfoHeight); 211 | } 212 | 213 | public Attacher getAttacher() { 214 | return mAttacher; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/uimanager/IGActivityLifecycleCallbacks.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.uimanager 2 | 3 | /** 4 | * Created by MLX on 2017/9/19. 5 | */ 6 | interface IGActivityLifecycleCallbacks { 7 | fun onCreated() 8 | fun onDestroyed() 9 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/uimanager/IGLoadHelper.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.uimanager 2 | 3 | import android.view.View 4 | 5 | interface IGLoadHelper { 6 | 7 | fun getContentView(): View 8 | 9 | fun showProgress() 10 | 11 | fun showContent() 12 | 13 | fun showEmpty() 14 | 15 | 16 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/uimanager/IGRecycler.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.uimanager 2 | 3 | import com.loopeer.android.librarys.imagegroupview.adapter.RecyclerViewAdapter 4 | import com.loopeer.android.librarys.imagegroupview.model.ImageFolder 5 | import com.loopeer.android.librarys.imagegroupview.uimanager.recycler.IGUIPattern 6 | 7 | interface IGRecycler:IGUIPattern{ 8 | fun createRecyclerViewAdapter():RecyclerViewAdapter 9 | fun adapterUpdateContentView(recyclerViewAdapter: RecyclerViewAdapter<*>, folder: ImageFolder?) 10 | } 11 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/uimanager/recycler/IGLoad.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.uimanager.recycler 2 | 3 | import android.content.Context 4 | import android.view.View 5 | import android.widget.ViewAnimator 6 | import com.loopeer.android.librarys.imagegroupview.R 7 | import com.loopeer.android.librarys.imagegroupview.uimanager.IGLoadHelper 8 | 9 | 10 | class IGLoad (context: Context,viewAnimator: ViewAnimator) :IGLoadHelper{ 11 | 12 | private val mEmptyIndex: Int 13 | private val mProgressIndex: Int 14 | private val mContentIndex: Int 15 | 16 | 17 | var mContext:Context 18 | var mViewAnimator:ViewAnimator 19 | 20 | init { 21 | mContext=context 22 | mViewAnimator=viewAnimator 23 | 24 | 25 | mEmptyIndex=mViewAnimator.indexOfChild(mViewAnimator.findViewById(R.id.text_album_empty)) 26 | mProgressIndex=mViewAnimator.indexOfChild(mViewAnimator.findViewById(R.id.progress_album)) 27 | mContentIndex=mViewAnimator.indexOfChild(mViewAnimator.findViewById(R.id.recycler_album)) 28 | } 29 | 30 | 31 | override fun getContentView(): View { 32 | return mViewAnimator.getChildAt(mContentIndex) 33 | } 34 | 35 | override fun showProgress() { 36 | mViewAnimator.displayedChild=mProgressIndex 37 | } 38 | 39 | override fun showContent() { 40 | mViewAnimator.displayedChild = mContentIndex 41 | } 42 | 43 | override fun showEmpty() { 44 | mViewAnimator.displayedChild = mEmptyIndex 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/uimanager/recycler/IGUIPattern.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.uimanager.recycler 2 | 3 | 4 | interface IGUIPattern { 5 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/uimanager/recycler/ImageGroupActivityManager.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.uimanager.recycler 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.view.View 6 | import android.widget.ViewAnimator 7 | import com.loopeer.android.librarys.imagegroupview.R 8 | import com.loopeer.android.librarys.imagegroupview.model.ImageFolder 9 | import com.loopeer.android.librarys.imagegroupview.uimanager.IGActivityLifecycleCallbacks 10 | import com.loopeer.android.librarys.imagegroupview.uimanager.IGLoadHelper 11 | import com.loopeer.android.librarys.imagegroupview.uimanager.IGRecycler 12 | 13 | 14 | open class ImageGroupActivityManager(context: Context, igRecycler: IGRecycler) : ImageGroupUIManager(context, igRecycler), IGActivityLifecycleCallbacks { 15 | 16 | 17 | override fun onCreated() { 18 | setUpLoadHelper() 19 | initAdapter() 20 | setUpView() 21 | } 22 | 23 | 24 | 25 | override fun setUpLoadHelper() { 26 | mLoadHelper = IGLoad(mContext!!, (mContext as Activity).findViewById(R.id.view_album_animator)) 27 | } 28 | 29 | 30 | override fun onDestroyed() { 31 | destroyAdapter() 32 | cleanRecyclerView() 33 | } 34 | 35 | 36 | override fun isFinishing(): Boolean { 37 | return (mContext as Activity).isFinishing 38 | } 39 | 40 | override fun onFolderItemSelected(imageFolder: ImageFolder?) { 41 | updateContentView(imageFolder) 42 | } 43 | 44 | 45 | 46 | private fun updateContentView(folder: ImageFolder?) { 47 | if (folder?.images?.size == 0) { 48 | mLoadHelper?.showEmpty() 49 | } else { 50 | mLoadHelper?.showContent() 51 | } 52 | mIGRcycler?.adapterUpdateContentView(madapter!!,folder) 53 | mRecyclerView?.scrollToPosition(0) 54 | } 55 | 56 | 57 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/uimanager/recycler/ImageGroupUIManager.kt: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.uimanager.recycler 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.support.v7.widget.GridLayoutManager 6 | import android.support.v7.widget.RecyclerView 7 | import android.util.Log 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.widget.ViewAnimator 11 | import com.loopeer.android.librarys.imagegroupview.R 12 | import com.loopeer.android.librarys.imagegroupview.adapter.RecyclerViewAdapter 13 | import com.loopeer.android.librarys.imagegroupview.uimanager.IGLoadHelper 14 | import com.loopeer.android.librarys.imagegroupview.uimanager.IGRecycler 15 | import com.loopeer.android.librarys.imagegroupview.view.CustomPopupView 16 | import com.loopeer.android.librarys.imagegroupview.view.DividerItemImagesDecoration 17 | 18 | abstract class ImageGroupUIManager(context: Context, igRecycler: IGRecycler) : CustomPopupView.FolderItemSelectListener { 19 | 20 | protected var mRecyclerView: RecyclerView? = null 21 | protected var mCustomPopupWindowView: CustomPopupView? = null 22 | private var mViewAnimator: ViewAnimator? = null 23 | var mContext: Context? 24 | protected var madapter: RecyclerViewAdapter? = null 25 | protected var mIGRcycler: IGRecycler? = null 26 | protected var mItems = mutableListOf() 27 | protected var mLoadHelper: IGLoadHelper? = null 28 | 29 | 30 | init { 31 | mContext = context 32 | mIGRcycler = igRecycler 33 | } 34 | 35 | protected fun setUpView() { 36 | initView() 37 | setUpTextView() 38 | setupRecyclerView() 39 | } 40 | 41 | private fun setUpTextView() { 42 | mCustomPopupWindowView?.setNumText(mContext?.getString(R.string.album_all)) 43 | mCustomPopupWindowView?.setFolderItemSelectListener(this) 44 | } 45 | 46 | fun getAdapter(): RecyclerViewAdapter<*>? { 47 | return madapter 48 | } 49 | 50 | fun getCustomPopupView(): CustomPopupView? { 51 | return mCustomPopupWindowView 52 | } 53 | 54 | protected fun initAdapter() { 55 | madapter = mIGRcycler?.createRecyclerViewAdapter() 56 | } 57 | 58 | protected abstract fun isFinishing(): Boolean 59 | 60 | protected abstract fun setUpLoadHelper() 61 | 62 | fun updateRecyclerView() { 63 | if (isFinishing()) return 64 | } 65 | 66 | private fun setupRecyclerView() { 67 | mRecyclerView?.layoutManager = GridLayoutManager(mContext, 3) 68 | mRecyclerView?.addItemDecoration( 69 | DividerItemImagesDecoration( 70 | mContext?.resources?.getDimensionPixelSize(R.dimen.inline_padding)!!)) 71 | mRecyclerView?.let { 72 | it.setPadding( 73 | mContext?.resources?.getDimensionPixelSize(R.dimen.inline_padding)!! / 2, 74 | 0, 75 | mContext?.resources?.getDimensionPixelSize(R.dimen.inline_padding)!! / 2, 76 | 0 77 | ) 78 | } 79 | mRecyclerView?.adapter = madapter 80 | } 81 | 82 | private fun initView() { 83 | mRecyclerView = mLoadHelper?.getContentView() as RecyclerView? 84 | val activity= mContext as Activity 85 | mCustomPopupWindowView= activity.findViewById(R.id.view_popup_folder_window) 86 | } 87 | 88 | fun destroyAdapter() { 89 | madapter = null 90 | } 91 | 92 | fun cleanRecyclerView() { 93 | mRecyclerView?.adapter = null 94 | mRecyclerView?.layoutManager = null 95 | mRecyclerView = null 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/AnimatorScaleType.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import android.graphics.Matrix; 4 | import android.graphics.Rect; 5 | 6 | import com.facebook.drawee.drawable.ScalingUtils; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | public class AnimatorScaleType implements ScalingUtils.ScaleType { 12 | 13 | public static AnimatorScaleType INSTANCE = new AnimatorScaleType(); 14 | 15 | private static final String ZOOM = "zoom"; 16 | private static final String REDUCE = "reduce"; 17 | public static final float ZOOM_SCALE = 0.2f; 18 | public static final float REDUCE_SCALE = 0.0f; 19 | private static Map POOL_INSTANCE = new HashMap<>(); 20 | 21 | static { 22 | if (!POOL_INSTANCE.containsKey(ZOOM)) { 23 | POOL_INSTANCE.put(ZOOM, new AnimatorScaleType(ZOOM_SCALE)); 24 | } 25 | if (!POOL_INSTANCE.containsKey(REDUCE)) { 26 | POOL_INSTANCE.put(REDUCE, new AnimatorScaleType(REDUCE_SCALE)); 27 | } 28 | } 29 | 30 | public static AnimatorScaleType getZoomScaleType() { 31 | return POOL_INSTANCE.get(ZOOM); 32 | } 33 | 34 | public static AnimatorScaleType getReduceScaleType() { 35 | return POOL_INSTANCE.get(REDUCE); 36 | } 37 | 38 | private AnimatorScaleType() { 39 | } 40 | 41 | private AnimatorScaleType(float scale) { 42 | mScale = scale; 43 | } 44 | 45 | private float mScale; 46 | 47 | public void setScale(float scale) { 48 | mScale = scale; 49 | } 50 | 51 | @Override 52 | public Matrix getTransform(Matrix outTransform, Rect parentRect, int childWidth, int childHeight, float focusX, float focusY) { 53 | float scale, dx, dy; 54 | final float scaleX = (float) parentRect.width() / (float) childWidth; 55 | final float scaleY = (float) parentRect.height() / (float) childHeight; 56 | if (scaleY > scaleX) { 57 | scale = scaleY; 58 | dx = parentRect.left + (parentRect.width() - childWidth * scale) * 0.5f; 59 | dy = parentRect.top; 60 | } else { 61 | scale = scaleX; 62 | dx = parentRect.left; 63 | dy = parentRect.top + (parentRect.height() - childHeight * scale) * 0.5f; 64 | } 65 | outTransform.setScale(scale, scale); 66 | outTransform.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f)); 67 | outTransform.postScale(1 + mScale, 1 + mScale, parentRect.width() / 2, parentRect.height() / 2); 68 | return outTransform; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/DisplayUtils.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Point; 6 | import android.os.Build; 7 | import android.view.Display; 8 | import android.view.WindowManager; 9 | 10 | import java.lang.reflect.Field; 11 | 12 | public class DisplayUtils { 13 | 14 | public static int getWindowHeight(Context context) { 15 | return getWindowPoint(context).y; 16 | } 17 | 18 | private static Point getWindowPoint(Context context) { 19 | Display display = ((Activity) context).getWindowManager().getDefaultDisplay(); 20 | Point size = new Point(); 21 | display.getSize(size); 22 | return size; 23 | } 24 | 25 | /** 26 | * 将px值转换为dip或dp值,保证尺寸大小不变 27 | * 28 | * @param pxValue 29 | * @param (DisplayMetrics类中属性density) 30 | * @return 31 | */ 32 | public static int px2dip(Context context, float pxValue) { 33 | final float scale = context.getResources().getDisplayMetrics().density; 34 | return (int) (pxValue / scale + 0.5f); 35 | } 36 | 37 | /** 38 | * 将dip或dp值转换为px值,保证尺寸大小不变 39 | * 40 | * @param dipValue 41 | * @param (DisplayMetrics类中属性density) 42 | * @return 43 | */ 44 | public static int dip2px(Context context, float dipValue) { 45 | final float scale = context.getResources().getDisplayMetrics().density; 46 | return (int) (dipValue * scale + 0.5f); 47 | } 48 | 49 | /** 50 | * 将px值转换为sp值,保证文字大小不变 51 | * 52 | * @param pxValue 53 | * @param (DisplayMetrics类中属性scaledDensity) 54 | * @return 55 | */ 56 | public static int px2sp(Context context, float pxValue) { 57 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 58 | return (int) (pxValue / fontScale + 0.5f); 59 | } 60 | 61 | /** 62 | * 将sp值转换为px值,保证文字大小不变 63 | * 64 | * @param spValue 65 | * @param (DisplayMetrics类中属性scaledDensity) 66 | * @return 67 | */ 68 | public static int sp2px(Context context, float spValue) { 69 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 70 | return (int) (spValue * fontScale + 0.5f); 71 | } 72 | 73 | public static int getScreenWidth(Context context) { 74 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 75 | return wm.getDefaultDisplay().getWidth(); 76 | } 77 | 78 | public static int getScreenHeight(Context context) { 79 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 80 | return wm.getDefaultDisplay().getHeight(); 81 | } 82 | 83 | public static int getStatusBarHeight(Context context) { 84 | Class c; 85 | Object obj; 86 | Field field; 87 | 88 | int x, statusBarHeight = 0; 89 | try { 90 | c = Class.forName("com.android.internal.R$dimen"); 91 | obj = c.newInstance(); 92 | field = c.getField("status_bar_height"); 93 | x = Integer.parseInt(field.get(obj).toString()); 94 | statusBarHeight = context.getResources().getDimensionPixelSize(x); 95 | } catch (Exception e1) { 96 | e1.printStackTrace(); 97 | } 98 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 99 | return 0; 100 | } else { 101 | return statusBarHeight; 102 | } 103 | 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | 6 | public class FileUtils { 7 | 8 | public static void deleteFile(File file) { 9 | if (file.exists()) { 10 | if (file.isFile()) { 11 | file.delete(); 12 | } else if (file.isDirectory()) { 13 | File files[] = file.listFiles(); 14 | for (int i = 0; i < files.length; i++) { 15 | deleteFile(files[i]); 16 | } 17 | } 18 | file.delete(); 19 | } else { 20 | 21 | } 22 | } 23 | 24 | public static long getFileSizes(File f) throws Exception { 25 | long s = 0; 26 | if (f.exists()) { 27 | FileInputStream fis = null; 28 | fis = new FileInputStream(f); 29 | s = fis.available(); 30 | } else { 31 | f.createNewFile(); 32 | System.out.println("文件不存在"); 33 | } 34 | return s; 35 | } 36 | 37 | public static boolean fileIsAvaliableImage(File f) throws Exception { 38 | long s; 39 | if (f.exists()) { 40 | FileInputStream fis; 41 | fis = new FileInputStream(f); 42 | s = fis.available(); 43 | } else { 44 | f.createNewFile(); 45 | return false; 46 | } 47 | return s > 1000 * 2; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/ImageGroupSavedState.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | import android.view.View; 6 | 7 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 8 | 9 | import java.util.List; 10 | 11 | public class ImageGroupSavedState extends View.BaseSavedState { 12 | 13 | private int doingClickViewId; 14 | private List squarePhotos; 15 | 16 | public ImageGroupSavedState(Parcelable superState) { 17 | super(superState); 18 | } 19 | 20 | public ImageGroupSavedState(Parcel source) { 21 | super(source); 22 | doingClickViewId = source.readInt(); 23 | squarePhotos = source.readArrayList(SquareImage.class.getClassLoader()); 24 | } 25 | 26 | public List getSquarePhotos() { 27 | return squarePhotos; 28 | } 29 | 30 | public void setSquarePhotos(List squarePhotos) { 31 | this.squarePhotos = squarePhotos; 32 | } 33 | 34 | public int getDoingClickViewId() { 35 | return doingClickViewId; 36 | } 37 | 38 | public void setDoingClickViewId(int doingClickViewId) { 39 | this.doingClickViewId = doingClickViewId; 40 | } 41 | 42 | @Override 43 | public void writeToParcel(Parcel out, int flags) { 44 | super.writeToParcel(out, flags); 45 | out.writeInt(this.doingClickViewId); 46 | out.writeArray(squarePhotos.toArray()); 47 | } 48 | 49 | public static final Creator CREATOR = 50 | new Creator() { 51 | public ImageGroupSavedState createFromParcel(Parcel in) { 52 | return new ImageGroupSavedState(in); 53 | } 54 | 55 | public ImageGroupSavedState[] newArray(int size) { 56 | return new ImageGroupSavedState[size]; 57 | } 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/ImageGroupUtils.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | import android.provider.MediaStore; 7 | 8 | public class ImageGroupUtils { 9 | 10 | public static String getPathOfPhotoByUri(Context context, Uri uri) { 11 | String[] filePathColumn = {MediaStore.Images.Media.DATA}; 12 | Cursor cursor = null; 13 | try { 14 | cursor = MediaStore.Images.Media.query(context.getContentResolver(), uri, filePathColumn); 15 | if (cursor != null && cursor.moveToFirst()) { 16 | int columnIndex = cursor.getColumnIndex(filePathColumn[0]); 17 | return cursor.getString(columnIndex); 18 | } 19 | } catch (Exception e) { 20 | e.printStackTrace(); 21 | } finally { 22 | if (cursor != null) 23 | cursor.close(); 24 | } 25 | return null; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/ImageUploadHandler.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | public class ImageUploadHandler extends Handler { 7 | 8 | public final static int HANDLER_START = 1; 9 | public final static int HANDLER_COMPLETE = 2; 10 | 11 | private ImageUploadHelper.OnImageUploadListener listener; 12 | 13 | public ImageUploadHandler(ImageUploadHelper.OnImageUploadListener listener) { 14 | this.listener = listener; 15 | } 16 | 17 | @Override 18 | public void handleMessage(Message msg) { 19 | switch (msg.what) { 20 | case HANDLER_START: 21 | listener.onImageUploadStart(); 22 | break; 23 | case HANDLER_COMPLETE: 24 | listener.onImageUploadComplete(); 25 | break; 26 | } 27 | } 28 | 29 | public void onHandleStart() { 30 | Message message = new Message(); 31 | message.what = HANDLER_START; 32 | sendMessage(message); 33 | } 34 | 35 | public void onHandleComplete() { 36 | Message message = new Message(); 37 | message.what = HANDLER_COMPLETE; 38 | sendMessage(message); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/ImageUploadHelper.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class ImageUploadHelper { 9 | 10 | public interface OnImageUploadListener { 11 | void onImageUploadStart(); 12 | 13 | void onImageUploadComplete(); 14 | } 15 | 16 | private OnImageUploadListener mListener; 17 | private ImageUploadHandler mHandler; 18 | private Thread mThread; 19 | private String mToken; 20 | private List mUrlList = new ArrayList<>(); 21 | private HashMap mTmpMap = new HashMap<>(); 22 | 23 | private static ImageUploadHelper INSTANCE; 24 | 25 | public static ImageUploadHelper getINSTANCE() { 26 | if (INSTANCE == null) { 27 | INSTANCE = new ImageUploadHelper(); 28 | } 29 | return INSTANCE; 30 | } 31 | 32 | //called when finish activity/fragment 33 | public void stopThread() { 34 | if (mThread != null) { 35 | mThread.interrupt(); 36 | mThread = null; 37 | } 38 | if (mHandler != null) { 39 | mHandler = null; 40 | } 41 | if (mListener != null) { 42 | mListener = null; 43 | } 44 | } 45 | 46 | public void upload(final HashMap map, String token, OnImageUploadListener listener) { 47 | mTmpMap.clear(); 48 | for (Map.Entry entry : map.entrySet()) { 49 | if (entry.getValue() != null && entry.getKey() != null) { 50 | if (!mUrlList.contains(entry.getValue())) { 51 | mTmpMap.put(entry.getKey(), entry.getValue()); 52 | mUrlList.add(entry.getValue()); 53 | } 54 | } 55 | } 56 | 57 | this.mListener = listener; 58 | this.mToken = token; 59 | mHandler = new ImageUploadHandler(mListener); 60 | mHandler.onHandleStart(); 61 | doUpload(mTmpMap); 62 | } 63 | 64 | private void doUpload(final HashMap map) { 65 | mThread = new Thread(new Runnable() { 66 | @Override 67 | public void run() { 68 | if (map == null || map.isEmpty()) { 69 | onFinish(); 70 | return; 71 | } 72 | for (Map.Entry entry : map.entrySet()) { 73 | if (entry.getValue() != null && entry.getKey() != null) { 74 | doUploadImage(entry.getValue(), entry.getKey(), map); 75 | break; 76 | } 77 | } 78 | } 79 | }); 80 | mThread.start(); 81 | } 82 | 83 | private void doUploadImage(String url, String key, final HashMap map) { 84 | // Bitmap scalebmp = ImageUtils.imageZoomByScreen(getAppContext(), url); 85 | // byte[] bytes = ImageUtils.compressImage(scalebmp); 86 | // if (TextUtils.isEmpty(mToken)) { 87 | // onFinish(); 88 | // return; 89 | // } 90 | // 91 | // Configuration config = new Configuration.Builder() 92 | // .zone(BuildConfig.DEBUG ? Zone.zone0 : Zone.zoneNa0) // 设置区域,指定不同区域的上传域名、备用域名、备用IP。 93 | // .build(); 94 | // UploadManager uploadManager = new UploadManager(config); 95 | // uploadManager.put(bytes, key, mToken, new UpCompletionHandler() { 96 | // @Override 97 | // public void complete(String key, ResponseInfo info, JSONObject response) { 98 | // map.remove(key); 99 | // doUpload(map); 100 | // } 101 | // }, null); 102 | 103 | } 104 | 105 | private void onFinish() { 106 | mHandler.onHandleComplete(); 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/utils/PermissionUtils.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.utils; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager; 8 | import android.os.Build; 9 | import android.support.v4.app.ActivityCompat; 10 | import android.support.v4.util.SimpleArrayMap; 11 | 12 | import static android.support.v4.content.PermissionChecker.checkSelfPermission; 13 | 14 | public final class PermissionUtils { 15 | 16 | // Map of dangerous permissions introduced in later framework versions. 17 | // Used to conditionally bypass permission-hold checks on older devices. 18 | private static final SimpleArrayMap MIN_SDK_PERMISSIONS; 19 | 20 | static { 21 | MIN_SDK_PERMISSIONS = new SimpleArrayMap<>(8); 22 | MIN_SDK_PERMISSIONS.put("com.android.voicemail.permission.ADD_VOICEMAIL", 14); 23 | MIN_SDK_PERMISSIONS.put("android.permission.BODY_SENSORS", 20); 24 | MIN_SDK_PERMISSIONS.put("android.permission.READ_CALL_LOG", 16); 25 | MIN_SDK_PERMISSIONS.put("android.permission.READ_EXTERNAL_STORAGE", 16); 26 | MIN_SDK_PERMISSIONS.put("android.permission.USE_SIP", 9); 27 | MIN_SDK_PERMISSIONS.put("android.permission.WRITE_CALL_LOG", 16); 28 | MIN_SDK_PERMISSIONS.put("android.permission.SYSTEM_ALERT_WINDOW", 23); 29 | MIN_SDK_PERMISSIONS.put("android.permission.WRITE_SETTINGS", 23); 30 | } 31 | 32 | private static volatile int targetSdkVersion = -1; 33 | 34 | private PermissionUtils() { 35 | } 36 | 37 | /** 38 | * Checks all given permissions have been granted. 39 | * 40 | * @param grantResults results 41 | * @return returns true if all permissions have been granted. 42 | */ 43 | public static boolean verifyPermissions(int... grantResults) { 44 | if (grantResults.length == 0) { 45 | return false; 46 | } 47 | for (int result : grantResults) { 48 | if (result != PackageManager.PERMISSION_GRANTED) { 49 | return false; 50 | } 51 | } 52 | return true; 53 | } 54 | 55 | /** 56 | * Returns true if the permission exists in this SDK version 57 | * 58 | * @param permission permission 59 | * @return returns true if the permission exists in this SDK version 60 | */ 61 | private static boolean permissionExists(String permission) { 62 | // Check if the permission could potentially be missing on this device 63 | Integer minVersion = MIN_SDK_PERMISSIONS.get(permission); 64 | // If null was returned from the above call, there is no need for a device API level check for the permission; 65 | // otherwise, we check if its minimum API level requirement is met 66 | return minVersion == null || Build.VERSION.SDK_INT >= minVersion; 67 | } 68 | 69 | /** 70 | * Returns true if the Activity or Fragment has access to all given permissions. 71 | * 72 | * @param context context 73 | * @param permissions permission list 74 | * @return returns true if the Activity or Fragment has access to all given permissions. 75 | */ 76 | public static boolean hasSelfPermissions(Context context, String... permissions) { 77 | for (String permission : permissions) { 78 | if (permissionExists(permission) && !hasSelfPermission(context, permission)) { 79 | return false; 80 | } 81 | } 82 | return true; 83 | } 84 | 85 | /** 86 | * Determine context has access to the given permission. 87 | * 88 | * This is a workaround for RuntimeException of Parcel#readException. 89 | * For more detail, check this issue https://github.com/hotchemi/PermissionsDispatcher/issues/107 90 | * 91 | * @param context context 92 | * @param permission permission 93 | * @return returns true if context has access to the given permission, false otherwise. 94 | * @see #hasSelfPermissions(Context, String...) 95 | */ 96 | private static boolean hasSelfPermission(Context context, String permission) { 97 | try { 98 | return checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; 99 | } catch (RuntimeException t) { 100 | return false; 101 | } 102 | } 103 | 104 | /** 105 | * Checks given permissions are needed to show rationale. 106 | * 107 | * @param activity activity 108 | * @param permissions permission list 109 | * @return returns true if one of the permission is needed to show rationale. 110 | */ 111 | public static boolean shouldShowRequestPermissionRationale(Activity activity, String... permissions) { 112 | for (String permission : permissions) { 113 | if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { 114 | return true; 115 | } 116 | } 117 | return false; 118 | } 119 | 120 | /** 121 | * Get target sdk version. 122 | * 123 | * @param context context 124 | * @return target sdk version 125 | */ 126 | @TargetApi(Build.VERSION_CODES.DONUT) 127 | public static int getTargetSdkVersion(Context context) { 128 | if (targetSdkVersion != -1) { 129 | return targetSdkVersion; 130 | } 131 | try { 132 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 133 | targetSdkVersion = packageInfo.applicationInfo.targetSdkVersion; 134 | } catch (PackageManager.NameNotFoundException ignored) { 135 | } 136 | return targetSdkVersion; 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/CustomFragmentPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.os.Parcelable; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentTransaction; 7 | import android.support.v4.view.PagerAdapter; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | public abstract class CustomFragmentPagerAdapter extends PagerAdapter { 13 | private static final String TAG = "FragmentPagerAdapter"; 14 | private static final boolean DEBUG = false; 15 | 16 | private final FragmentManager mFragmentManager; 17 | private FragmentTransaction mCurTransaction = null; 18 | private Fragment mCurrentPrimaryItem = null; 19 | 20 | public CustomFragmentPagerAdapter(FragmentManager fm) { 21 | mFragmentManager = fm; 22 | } 23 | 24 | /** 25 | * Return the Fragment associated with a specified position. 26 | */ 27 | public abstract Fragment getItem(int position); 28 | 29 | @Override 30 | public void startUpdate(ViewGroup container) { 31 | if (container.getId() == View.NO_ID) { 32 | throw new IllegalStateException("ViewPager with adapter " + this 33 | + " requires a view id"); 34 | } 35 | } 36 | 37 | @Override 38 | public Object instantiateItem(ViewGroup container, int position) { 39 | if (mCurTransaction == null) { 40 | mCurTransaction = mFragmentManager.beginTransaction(); 41 | } 42 | 43 | final long itemId = getItemId(position); 44 | 45 | // Do we already have this fragment? 46 | String name = makeFragmentName(position); 47 | Fragment fragment = mFragmentManager.findFragmentByTag(name); 48 | if (fragment != null) { 49 | if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); 50 | mCurTransaction.attach(fragment); 51 | } else { 52 | fragment = getItem(position); 53 | if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); 54 | mCurTransaction.add(container.getId(), fragment, 55 | makeFragmentName(position)); 56 | } 57 | if (fragment != mCurrentPrimaryItem) { 58 | fragment.setMenuVisibility(false); 59 | fragment.setUserVisibleHint(false); 60 | } 61 | 62 | return fragment; 63 | } 64 | 65 | public static String makeFragmentName(int position) { 66 | return "android:switcher:" + position; 67 | } 68 | 69 | @Override 70 | public void destroyItem(ViewGroup container, int position, Object object) { 71 | if (mCurTransaction == null) { 72 | mCurTransaction = mFragmentManager.beginTransaction(); 73 | } 74 | if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object 75 | + " v=" + ((Fragment)object).getView()); 76 | mCurTransaction.detach((Fragment)object); 77 | } 78 | 79 | @Override 80 | public void setPrimaryItem(ViewGroup container, int position, Object object) { 81 | Fragment fragment = (Fragment)object; 82 | if (fragment != mCurrentPrimaryItem) { 83 | if (mCurrentPrimaryItem != null) { 84 | mCurrentPrimaryItem.setMenuVisibility(false); 85 | mCurrentPrimaryItem.setUserVisibleHint(false); 86 | } 87 | if (fragment != null) { 88 | fragment.setMenuVisibility(true); 89 | fragment.setUserVisibleHint(true); 90 | } 91 | mCurrentPrimaryItem = fragment; 92 | } 93 | } 94 | 95 | @Override 96 | public void finishUpdate(ViewGroup container) { 97 | if (mCurTransaction != null) { 98 | mCurTransaction.commitNowAllowingStateLoss(); 99 | mCurTransaction = null; 100 | } 101 | } 102 | 103 | @Override 104 | public boolean isViewFromObject(View view, Object object) { 105 | return ((Fragment)object).getView() == view; 106 | } 107 | 108 | @Override 109 | public Parcelable saveState() { 110 | return null; 111 | } 112 | 113 | @Override 114 | public void restoreState(Parcelable state, ClassLoader loader) { 115 | } 116 | 117 | /** 118 | * Return a unique identifier for the item at the given position. 119 | * 120 | *

The default implementation returns the given position. 121 | * Subclasses should override this method if the positions of items can change.

122 | * 123 | * @param position Position within this adapter 124 | * @return Unique identifier for the item at position 125 | */ 126 | public long getItemId(int position) { 127 | return position; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/CustomPopupView.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.LinearLayout; 12 | import android.widget.TextView; 13 | 14 | import com.loopeer.android.librarys.imagegroupview.R; 15 | import com.loopeer.android.librarys.imagegroupview.adapter.AlbumRecyclerAdapter; 16 | import com.loopeer.android.librarys.imagegroupview.model.ImageFolder; 17 | import com.loopeer.android.librarys.imagegroupview.utils.DisplayUtils; 18 | 19 | import java.util.List; 20 | 21 | public class CustomPopupView extends LinearLayout implements View.OnClickListener, AlbumRecyclerAdapter.OnItemClickListener { 22 | 23 | private View mBgView; 24 | private RecyclerView mRecyclerView; 25 | private TextView mTextImagesNum; 26 | private AlbumRecyclerAdapter mFolderRecyclerAdaper; 27 | private boolean mIsShowing; 28 | private FolderItemSelectListener mFolderItemSelectListener; 29 | 30 | public CustomPopupView(Context context) { 31 | this(context, null); 32 | } 33 | 34 | public CustomPopupView(Context context, AttributeSet attrs) { 35 | this(context, attrs, 0); 36 | } 37 | 38 | public CustomPopupView(Context context, AttributeSet attrs, int defStyleAttr) { 39 | super(context, attrs, defStyleAttr); 40 | init(); 41 | } 42 | 43 | private void init() { 44 | LayoutInflater.from(getContext()).inflate(R.layout.view_popup_folder, this); 45 | mBgView = findViewById(R.id.view_album_popup_bg); 46 | mRecyclerView = (RecyclerView) findViewById(R.id.recycler_album_popup); 47 | mTextImagesNum = (TextView) findViewById(R.id.text_images_num); 48 | 49 | mFolderRecyclerAdaper = new AlbumRecyclerAdapter(getContext()); 50 | mFolderRecyclerAdaper.setOnItemClickListener(this); 51 | mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 52 | mRecyclerView.setAdapter(mFolderRecyclerAdaper); 53 | mTextImagesNum.setOnClickListener(this); 54 | mBgView.setOnClickListener(this); 55 | } 56 | 57 | private void show() { 58 | mIsShowing = true; 59 | startShowWindowAnimation(); 60 | } 61 | 62 | public void dismiss() { 63 | mIsShowing = false; 64 | startDismissWindowAnimation(); 65 | } 66 | 67 | private boolean isShowing() { 68 | return mIsShowing; 69 | } 70 | 71 | private void togglePopupWindow() { 72 | if (isShowing()) { 73 | dismiss(); 74 | } else { 75 | show(); 76 | } 77 | } 78 | 79 | private void startShowWindowAnimation() { 80 | startShowAnimation(0, calculateWindowHeight(), true); 81 | } 82 | 83 | private void startDismissWindowAnimation() { 84 | startShowAnimation(calculateWindowHeight(), 0, false); 85 | } 86 | 87 | private void startShowAnimation(final int startHeight, final int endHeight, final boolean isShow) { 88 | ValueAnimator valueAnimator = ValueAnimator.ofInt(startHeight, endHeight); 89 | valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 90 | @Override 91 | public void onAnimationUpdate(ValueAnimator animation) { 92 | int height = (int) animation.getAnimatedValue(); 93 | if (height == startHeight && isShow) { 94 | mRecyclerView.setVisibility(VISIBLE); 95 | mBgView.setVisibility(VISIBLE); 96 | } 97 | setRecyclerViewHeight(height); 98 | setBgViewAlpha((float) height / (float) Math.abs(endHeight - startHeight)); 99 | if (height == endHeight && !isShow) { 100 | mRecyclerView.setVisibility(GONE); 101 | mBgView.setVisibility(GONE); 102 | } 103 | } 104 | }); 105 | valueAnimator.start(); 106 | } 107 | 108 | private void setBgViewAlpha(float v) { 109 | mBgView.setAlpha(v); 110 | } 111 | 112 | private int getFooterHeight() { 113 | return mTextImagesNum.getHeight(); 114 | } 115 | 116 | private void setRecyclerViewHeight(int height) { 117 | ViewGroup.LayoutParams params = mRecyclerView.getLayoutParams(); 118 | params.height = height; 119 | mRecyclerView.setLayoutParams(params); 120 | } 121 | 122 | private int calculateWindowHeight() { 123 | int itemHeight = getResources().getDimensionPixelSize(R.dimen.image_select_folder_height); 124 | int actualHeight = mFolderRecyclerAdaper.getItemCount() * itemHeight; 125 | int maxPopupHeight = DisplayUtils.getScreenHeight(getContext()) * 5 / 8; 126 | return Math.min(maxPopupHeight, actualHeight); 127 | } 128 | 129 | public void setNumText(String str) { 130 | mTextImagesNum.setText(str); 131 | } 132 | 133 | public void updateFolderData(List list) { 134 | mFolderRecyclerAdaper.updateData(list); 135 | 136 | updateDefaultImages(); 137 | } 138 | 139 | public void setFolderItemSelectListener(FolderItemSelectListener listener) { 140 | mFolderItemSelectListener = listener; 141 | } 142 | 143 | private void updateDefaultImages() { 144 | onItemSelect(mFolderRecyclerAdaper.getItem(0)); 145 | } 146 | 147 | private void onItemSelect(ImageFolder item) { 148 | mTextImagesNum.setText(item.name); 149 | dismiss(); 150 | mFolderItemSelectListener.onFolderItemSelected(item); 151 | } 152 | 153 | @Override 154 | public void onClick(View v) { 155 | if (v.getId() == R.id.text_images_num) { 156 | togglePopupWindow(); 157 | } else if (v.getId() == R.id.view_album_popup_bg) { 158 | dismiss(); 159 | } 160 | 161 | } 162 | 163 | @Override 164 | public void onItemClick(ImageFolder imageFolder) { 165 | onItemSelect(imageFolder); 166 | } 167 | 168 | public interface FolderItemSelectListener { 169 | void onFolderItemSelected(ImageFolder imageFolder); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/DividerItemImagesDecoration.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.graphics.Rect; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | 7 | public class DividerItemImagesDecoration extends RecyclerView.ItemDecoration { 8 | 9 | private int mInsets; 10 | 11 | public DividerItemImagesDecoration(int insets) { 12 | mInsets = insets; 13 | } 14 | 15 | @Override 16 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 17 | super.getItemOffsets(outRect, view, parent, state); 18 | outRect.set(mInsets / 2, mInsets, mInsets / 2, 0); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/DragDismissFrameLayout.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.content.Context; 4 | import android.support.v4.content.ContextCompat; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.view.animation.AccelerateInterpolator; 8 | import android.widget.FrameLayout; 9 | 10 | import com.loopeer.android.librarys.imagegroupview.OnTabOneClickListener; 11 | import com.loopeer.android.librarys.imagegroupview.R; 12 | import com.loopeer.android.librarys.imagegroupview.photodraweeview.PhotoDraweeView; 13 | import com.loopeer.android.librarys.imagegroupview.utils.DisplayUtils; 14 | 15 | public class DragDismissFrameLayout extends FrameLayout { 16 | 17 | private PhotoDraweeView mPhotoDraweeView; 18 | private int mScreenHeight; 19 | private int mDragDismissDistance; 20 | private int mBlackColor; 21 | private int mWhiteColor; 22 | private boolean mIsMoving; 23 | private boolean mDragDismiss = true; 24 | 25 | public DragDismissFrameLayout(Context context) { 26 | this(context, null); 27 | } 28 | 29 | public DragDismissFrameLayout(Context context, AttributeSet attrs) { 30 | this(context, attrs, 0); 31 | } 32 | 33 | public DragDismissFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { 34 | super(context, attrs, defStyleAttr); 35 | init(); 36 | } 37 | 38 | public void setDragDismiss(boolean dragDismiss) { 39 | mDragDismiss = dragDismiss; 40 | } 41 | 42 | private void init() { 43 | mScreenHeight = DisplayUtils.getScreenHeight(getContext()); 44 | mDragDismissDistance = mScreenHeight / 8; 45 | mBlackColor = ContextCompat.getColor(getContext(), R.color.scale_bg_black); 46 | mWhiteColor = ContextCompat.getColor(getContext(), R.color.scale_bg_white); 47 | } 48 | 49 | public void setPhotoDraweeView(PhotoDraweeView photoDraweeView) { 50 | mPhotoDraweeView = photoDraweeView; 51 | } 52 | 53 | float downX, downY, moveX, moveY; 54 | 55 | @Override 56 | public boolean dispatchTouchEvent(MotionEvent event) { 57 | if (!mDragDismiss || mPhotoDraweeView == null) { 58 | return super.dispatchTouchEvent(event); 59 | } 60 | switch (event.getAction()) { 61 | case MotionEvent.ACTION_DOWN://手指刚接触屏幕 62 | downX = event.getX(); 63 | downY = event.getY(); 64 | break; 65 | case MotionEvent.ACTION_MOVE://手指在屏幕上移动 66 | moveX = event.getX(); 67 | moveY = event.getY(); 68 | if (!mIsMoving && mPhotoDraweeView.getScale() == mPhotoDraweeView.getMinimumScale() 69 | && moveY > downY && Math.abs(moveY - downY) > Math.abs(moveX - downX)) { 70 | mIsMoving = true; 71 | } 72 | 73 | if (mIsMoving) { 74 | mPhotoDraweeView.setTranslationX(moveX - downX); 75 | mPhotoDraweeView.setTranslationY(moveY - downY); 76 | float scale = calculateScale(moveY - downY); 77 | mPhotoDraweeView.setScaleX(scale); 78 | mPhotoDraweeView.setScaleY(scale); 79 | setBackgroundColor(calculateColor(calculateColorFraction(moveY - downY), mBlackColor, mWhiteColor)); 80 | } 81 | break; 82 | case MotionEvent.ACTION_UP: 83 | case MotionEvent.ACTION_CANCEL: 84 | if (mIsMoving) { 85 | moveTouchUp(); 86 | } 87 | mIsMoving = false; 88 | break; 89 | } 90 | return super.dispatchTouchEvent(event); 91 | } 92 | 93 | private void moveTouchUp() { 94 | if (mPhotoDraweeView.getTranslationY() >= mDragDismissDistance) { 95 | //消失 96 | if (getContext() instanceof OnTabOneClickListener) { 97 | ((OnTabOneClickListener) getContext()).onTabOneClick(); 98 | } 99 | } else { 100 | //复位 101 | doRestoreAnimation(); 102 | } 103 | } 104 | 105 | private void doRestoreAnimation() { 106 | setBackgroundColor(mBlackColor); 107 | mPhotoDraweeView.animate() 108 | .scaleX(1.0f) 109 | .scaleY(1.0f) 110 | .translationX(0.0f) 111 | .translationY(0.0f) 112 | .setDuration(100) 113 | .setInterpolator(new AccelerateInterpolator()) 114 | .start(); 115 | } 116 | 117 | private float calculateScale(float distance) { 118 | if (mPhotoDraweeView.getTranslationY() <= 0.0f) { 119 | return 1.0f; 120 | } 121 | return 1.0f - Math.abs(distance) / mScreenHeight; 122 | } 123 | 124 | private float calculateColorFraction(float distance) { 125 | if (mPhotoDraweeView.getTranslationY() <= 0.0f) { 126 | return 0.0f; 127 | } 128 | return Math.abs(distance) / mScreenHeight; 129 | } 130 | 131 | public int calculateColor(float fraction, int startColor, int endColor) { 132 | int startA = (startColor >> 24) & 0xff; 133 | int startR = (startColor >> 16) & 0xff; 134 | int startG = (startColor >> 8) & 0xff; 135 | int startB = startColor & 0xff; 136 | 137 | int endA = (endColor >> 24) & 0xff; 138 | int endR = (endColor >> 16) & 0xff; 139 | int endG = (endColor >> 8) & 0xff; 140 | int endB = endColor & 0xff; 141 | 142 | return (startA + (int) (fraction * (endA - startA))) << 24 | 143 | (startR + (int) (fraction * (endR - startR))) << 16 | 144 | (startG + (int) (fraction * (endG - startG))) << 8 | 145 | (startB + (int) (fraction * (endB - startB))); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/DragRecycleAdapter.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | 4 | import android.content.Context; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.AdapterView; 11 | 12 | import com.loopeer.android.librarys.imagegroupview.R; 13 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 14 | 15 | import java.util.Collections; 16 | import java.util.List; 17 | 18 | public class DragRecycleAdapter extends RecyclerView.Adapter implements View.OnClickListener, ItemTouchHelperAdapter { 19 | 20 | private Context context; 21 | public List mData;//九宫格图片 22 | private static int hidePosition = AdapterView.INVALID_POSITION; 23 | 24 | public DragRecycleAdapter(Context context, List data) { 25 | this.context = context; 26 | this.mData = data; 27 | } 28 | 29 | @Override 30 | public DragViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 31 | View view = LayoutInflater.from(context).inflate(R.layout.item_view, parent, false); 32 | return new DragViewHolder(view); 33 | } 34 | 35 | @Override 36 | public void onBindViewHolder(DragViewHolder holder, int position) { 37 | holder.squareView.setImageData(mData.get(position)); 38 | holder.itemView.setTag(position);//将position保存在itemView的Tag中,以便点击时进行获取 39 | } 40 | 41 | @Override 42 | public int getItemCount() { 43 | return mData.size(); 44 | } 45 | 46 | @Override 47 | public long getItemId(int position) { 48 | return super.getItemId(position); 49 | } 50 | 51 | @Override 52 | public void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { 53 | int fromPosition = source.getAdapterPosition(); 54 | int toPosition = target.getAdapterPosition(); 55 | if (fromPosition < mData.size() && toPosition < mData.size()) { 56 | //交换数据位置 57 | Collections.swap(mData, fromPosition, toPosition); 58 | //刷新位置交换 59 | int n = 0; 60 | for (SquareImage s : mData 61 | ) { 62 | Log.d("log ", "mdata " + n + s.localUrl); 63 | n++; 64 | } 65 | Log.d("log ", "============================================================="); 66 | notifyItemMoved(fromPosition, toPosition); 67 | } 68 | //移动过程中移除view的放大效果 69 | onItemClear(source); 70 | } 71 | 72 | @Override 73 | public void onItemDissmiss(RecyclerView.ViewHolder source) { 74 | int position = source.getAdapterPosition(); 75 | mData.remove(position); //移除数据 76 | notifyItemRemoved(position);//刷新数据移除 77 | } 78 | 79 | @Override 80 | public void onItemSelect(RecyclerView.ViewHolder source) { 81 | //当拖拽选中时放大选中的view 82 | source.itemView.setScaleX(1.2f); 83 | source.itemView.setScaleY(1.2f); 84 | } 85 | 86 | @Override 87 | public void onItemClear(RecyclerView.ViewHolder source) { 88 | //拖拽结束后恢复view的状态 89 | source.itemView.setScaleX(1.0f); 90 | source.itemView.setScaleY(1.0f); 91 | } 92 | 93 | @Override 94 | public void onClick(View v) { 95 | 96 | } 97 | 98 | static class DragViewHolder extends RecyclerView.ViewHolder { 99 | SquareImageView squareView; 100 | View mView; 101 | 102 | DragViewHolder(View itemView) { 103 | super(itemView); 104 | this.mView = itemView; 105 | squareView = (SquareImageView) itemView.findViewById(R.id.sq); 106 | squareView.setClickAble(true); 107 | } 108 | 109 | } 110 | 111 | //更新拖动时的gridView 112 | void swapView(int draggedPos, int destPos) { 113 | //从前向后拖动,其他item依次前移 114 | if (draggedPos < destPos) { 115 | mData.add(destPos + 1, mData.get(draggedPos)); 116 | mData.remove(draggedPos); 117 | } 118 | //从后向前拖动,其他item依次后移 119 | else if (draggedPos > destPos) { 120 | mData.add(destPos, mData.get(draggedPos)); 121 | mData.remove(draggedPos + 1); 122 | } 123 | } 124 | 125 | void removeView(int position) { 126 | mData.remove(position); 127 | int n = 0; 128 | for (SquareImage s : mData 129 | ) { 130 | Log.d("log ", "mdata " + n + s.localUrl); 131 | n++; 132 | } 133 | Log.d("log ", "============================================================="); 134 | notifyItemChanged(position); 135 | notifyDataSetChanged(); 136 | // notifyItemChanged(position); 137 | // Collections. 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/DragRecycleView.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | 4 | import android.content.Context; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.util.AttributeSet; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.view.WindowManager; 11 | import android.widget.AdapterView; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | public class DragRecycleView extends RecyclerView { 16 | private static final int DRAG_IMG_SHOW = 1;//滑动状态 17 | private static final int DRAG_IMG_NOT_SHOW = 0;//非滑动状态 18 | private static final float AMP_FACTOR = 1.2f; 19 | private static final String TAG = "DragRecycleView"; 20 | 21 | private ImageView dragImageView;//滑动的imageView 22 | private WindowManager.LayoutParams dragImageViewParams; 23 | private WindowManager windowManager; 24 | private boolean isViewOnDrag = false; 25 | 26 | public TextView tv; 27 | 28 | private int preDraggedOverPosition = AdapterView.INVALID_POSITION;//滑动前的位置 29 | private int downRawX; 30 | private int downRawY; 31 | private int sHeight; 32 | 33 | 34 | public DragRecycleView(Context context) { 35 | this(context, null); 36 | } 37 | 38 | public DragRecycleView(Context context, @Nullable AttributeSet attrs) { 39 | this(context, attrs, 0); 40 | } 41 | 42 | public DragRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) { 43 | super(context, attrs, defStyle); 44 | init(context, attrs, defStyle); 45 | } 46 | 47 | private void init(Context context, @Nullable AttributeSet attrs, int defStyle) { 48 | //初始化显示被拖动item的imageView 49 | //初始化用于设置dragImageView的参数对象 50 | // View.inflate(context, R.layout.drag_recycle, this); 51 | // tv = (TextView) findViewById(R.id.delete); 52 | dragImageView = new ImageView(getContext()); 53 | dragImageView.setTag(DRAG_IMG_NOT_SHOW); 54 | dragImageViewParams = new WindowManager.LayoutParams(); 55 | windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); 56 | WindowManager wm = (WindowManager) getContext() 57 | .getSystemService(Context.WINDOW_SERVICE); 58 | 59 | 60 | sHeight = wm.getDefaultDisplay().getHeight(); 61 | } 62 | 63 | @Override 64 | public boolean onTouchEvent(MotionEvent e) { 65 | DragRecycleAdapter adapter = (DragRecycleAdapter) getAdapter(); 66 | if (e.getAction() == MotionEvent.ACTION_DOWN) { 67 | 68 | } else if (e.getAction() == MotionEvent.ACTION_MOVE) { 69 | tv.setVisibility(VISIBLE); 70 | if (sHeight - e.getY() < 400) { 71 | tv.setText("松手即可删除"); 72 | }else{tv.setText("拖动到此处删除");} 73 | } else if (e.getAction() == MotionEvent.ACTION_UP) { 74 | View targetView = this.findChildViewUnder((int) e.getX(), (int) e.getY()); 75 | int currDraggedPosition = getChildAdapterPosition(targetView);//http://dalufan.com/2016/12/02/android-recycleview-useage-issues/在AbsListView(listview、gridview)中,有个根据屏幕位置获取pos的方法:pointToPosition,但在recycleview中没有这个方法,可以通过下面方法来达到相同的效果 76 | if (sHeight - e.getY() < 400) { 77 | adapter.removeView(currDraggedPosition); 78 | } 79 | tv.setVisibility(GONE); 80 | } 81 | return super.onTouchEvent(e); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/FixedNestedScrollView.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.content.Context; 4 | import android.support.v4.widget.NestedScrollView; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | 8 | public class FixedNestedScrollView extends NestedScrollView { 9 | public FixedNestedScrollView(Context context) { 10 | super(context); 11 | } 12 | 13 | public FixedNestedScrollView(Context context, AttributeSet attrs) { 14 | super(context, attrs); 15 | } 16 | 17 | public FixedNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 18 | super(context, attrs, defStyleAttr); 19 | } 20 | 21 | @Override 22 | public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { 23 | dispatchNestedPreScroll(0, dy, consumed, null); 24 | } 25 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/GridImageAdapter.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.AbsListView; 8 | import android.widget.BaseAdapter; 9 | 10 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class GridImageAdapter extends BaseAdapter { 16 | private Context mContext; 17 | private List mData; 18 | private OnSquareClickListener mClickListener; 19 | private int mAddButtonDrawable; 20 | private int mPlaceholderDrawable; 21 | private boolean mRoundAsCircle; 22 | 23 | public GridImageAdapter(Context c, OnSquareClickListener listener) { 24 | mContext = c; 25 | mData = new ArrayList<>(); 26 | mClickListener = listener; 27 | } 28 | 29 | public void updateParam(int addButtonDrawable, int placeholderDrawable, boolean roundAsCircle) { 30 | mAddButtonDrawable = addButtonDrawable; 31 | mPlaceholderDrawable = placeholderDrawable; 32 | mRoundAsCircle = roundAsCircle; 33 | notifyDataSetChanged(); 34 | } 35 | 36 | public void updateData(List datas, boolean showAddButton) { 37 | setData(datas, showAddButton); 38 | notifyDataSetChanged(); 39 | } 40 | 41 | public void setData(List datas, boolean showAddButton) { 42 | mData.clear(); 43 | mData.addAll(datas); 44 | if (showAddButton) { 45 | mData.add(null); 46 | } 47 | } 48 | 49 | public int getCount() { 50 | return mData.size(); 51 | } 52 | 53 | public SquareImage getItem(int position) { 54 | return mData.get(position); 55 | } 56 | 57 | public long getItemId(int position) { 58 | return 0; 59 | } 60 | 61 | public View getView(int position, View convertView, ViewGroup parent) { 62 | SquareImageView squareView; 63 | if (convertView == null || !convertView.getTag().equals(getTag(position))) { 64 | squareView = new SquareImageView(mContext); 65 | squareView.setPlaceholderDrawable(mPlaceholderDrawable); 66 | squareView.setRoundAsCircle(mRoundAsCircle); 67 | squareView.setLayoutParams(new AbsListView.LayoutParams(-1, -2)); 68 | squareView.setTag(getTag(position)); 69 | } else { 70 | squareView = (SquareImageView) convertView; 71 | } 72 | 73 | bindData(squareView, position); 74 | return squareView; 75 | } 76 | 77 | @NonNull 78 | private String getTag(int position) { 79 | return "POSITION" + position; 80 | } 81 | 82 | private void bindData(SquareImageView squareView, final int position) { 83 | if (getItem(position) == null) { 84 | squareView.setImageResource(mAddButtonDrawable); 85 | } else { 86 | squareView.setImageData(getItem(position)); 87 | } 88 | squareView.setOnClickListener(new View.OnClickListener() { 89 | @Override 90 | public void onClick(View v) { 91 | mClickListener.photoClick(v, getItem(position), position); 92 | } 93 | }); 94 | } 95 | 96 | interface OnSquareClickListener { 97 | void photoClick(View v, SquareImage squareImage, int position); 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/ItemTouchHelperAdapter.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | 4 | import android.support.v7.widget.RecyclerView; 5 | 6 | public interface ItemTouchHelperAdapter { 7 | //数据交换 8 | void onItemMove(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target); 9 | 10 | //数据删除 11 | void onItemDissmiss(RecyclerView.ViewHolder source); 12 | 13 | //drag或者swipe选中 14 | void onItemSelect(RecyclerView.ViewHolder source); 15 | 16 | //状态清除 17 | void onItemClear(RecyclerView.ViewHolder source); 18 | } 19 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/MutipleTouchViewPager.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | 8 | public class MutipleTouchViewPager extends ViewPager { 9 | 10 | public MutipleTouchViewPager(Context context) { 11 | super(context); 12 | } 13 | 14 | public MutipleTouchViewPager(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | private boolean mIsDisallowIntercept = false; 18 | @Override 19 | public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { 20 | mIsDisallowIntercept = disallowIntercept; 21 | super.requestDisallowInterceptTouchEvent(disallowIntercept); 22 | } 23 | 24 | @Override 25 | public boolean dispatchTouchEvent(MotionEvent ev) { 26 | if (ev.getPointerCount() > 1 && mIsDisallowIntercept) { 27 | requestDisallowInterceptTouchEvent(false); 28 | boolean handled = super.dispatchTouchEvent(ev); 29 | requestDisallowInterceptTouchEvent(true); 30 | return handled; 31 | } else { 32 | return super.dispatchTouchEvent(ev); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/ScaleImageView.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Matrix; 7 | import android.util.AttributeSet; 8 | 9 | import com.facebook.drawee.view.SimpleDraweeView; 10 | 11 | public class ScaleImageView extends SimpleDraweeView { 12 | 13 | private Matrix mMatrix; 14 | 15 | private static final float ZOOM_SCALE = 0.2f; 16 | private static final float REDUCE_SCALE = 0.0f; 17 | 18 | public ScaleImageView(Context context) { 19 | this(context, null); 20 | } 21 | 22 | public ScaleImageView(Context context, AttributeSet attrs) { 23 | this(context, attrs, 0); 24 | } 25 | 26 | public ScaleImageView(Context context, AttributeSet attrs, int defStyle) { 27 | super(context, attrs, defStyle); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | mMatrix = new Matrix(); 33 | } 34 | 35 | @Override 36 | protected void onDraw(Canvas canvas) { 37 | canvas.concat(mMatrix); 38 | super.onDraw(canvas); 39 | } 40 | 41 | public void setScale(float scale) { 42 | // mMatrix.setScale(1 + scale, 1+scale, getMeasuredWidth() / 2, getMeasuredWidth() / 2); 43 | mMatrix.setScale(1 + scale, 1+scale, getMeasuredWidth() / 2, getMeasuredWidth() / 2); 44 | invalidate(); 45 | } 46 | 47 | public static float getZoomScale() { 48 | return ZOOM_SCALE; 49 | } 50 | 51 | public static float getReduceScale() { 52 | return REDUCE_SCALE; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/SimpleItemTouchHelperCallback.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | 4 | import android.support.v7.widget.RecyclerView; 5 | import android.support.v7.widget.helper.ItemTouchHelper; 6 | 7 | public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { 8 | 9 | private ItemTouchHelperAdapter mAdapter; 10 | 11 | public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { 12 | mAdapter = adapter; 13 | } 14 | 15 | @Override 16 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 17 | //int dragFlags = ItemTouchHelperAdapter.UP | ItemTouchHelperAdapter.DOWN; //允许上下的拖动 18 | //int dragFlags =ItemTouchHelperAdapter.LEFT | ItemTouchHelperAdapter.RIGHT; //允许左右的拖动 19 | //int swipeFlags = ItemTouchHelperAdapter.LEFT; //只允许从右向左侧滑 20 | //int swipeFlags = ItemTouchHelperAdapter.DOWN; //只允许从上向下侧滑 21 | //一般使用makeMovementFlags(int,int)或makeFlag(int, int)来构造我们的返回值 22 | //makeMovementFlags(dragFlags, swipeFlags) 23 | 24 | int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; //允许上下左右的拖动 25 | return makeMovementFlags(dragFlags, 0); 26 | } 27 | 28 | @Override 29 | public boolean isLongPressDragEnabled() { 30 | return true;//长按启用拖拽 31 | } 32 | 33 | @Override 34 | public boolean isItemViewSwipeEnabled() { 35 | return true; //不启用拖拽删除 36 | } 37 | 38 | @Override 39 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { 40 | //通过接口传递拖拽交换数据的起始位置和目标位置的ViewHolder 41 | mAdapter.onItemMove(source, target); 42 | return true; 43 | } 44 | 45 | 46 | @Override 47 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 48 | //移动删除回调,如果不用可以不用理 49 | mAdapter.onItemDissmiss(viewHolder); 50 | } 51 | 52 | @Override 53 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { 54 | super.onSelectedChanged(viewHolder, actionState); 55 | if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { 56 | //当滑动或者拖拽view的时候通过接口返回该ViewHolder 57 | mAdapter.onItemSelect(viewHolder); 58 | } 59 | } 60 | 61 | @Override 62 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 63 | super.clearView(recyclerView, viewHolder); 64 | if (!recyclerView.isComputingLayout()) { 65 | //当需要清除之前在onSelectedChanged或者onChildDraw,onChildDrawOver设置的状态或者动画时通过接口返回该ViewHolder 66 | mAdapter.onItemClear(viewHolder); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/SingleImageView.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.content.Context; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.support.annotation.NonNull; 7 | import android.support.v7.app.AlertDialog; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 12 | import com.facebook.drawee.view.SimpleDraweeView; 13 | import com.loopeer.android.librarys.imagegroupview.NavigatorImage; 14 | import com.loopeer.android.librarys.imagegroupview.R; 15 | import com.loopeer.android.librarys.imagegroupview.activity.AlbumActivity; 16 | import com.loopeer.android.librarys.imagegroupview.model.Image; 17 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 18 | import com.loopeer.android.librarys.imagegroupview.utils.ImageGroupDisplayHelper; 19 | 20 | import java.util.List; 21 | 22 | public class SingleImageView extends SimpleDraweeView implements View.OnClickListener { 23 | 24 | private SquareImage mImage; 25 | private int mPlaceholderDrawable; 26 | 27 | public SingleImageView(Context context, GenericDraweeHierarchy hierarchy) { 28 | super(context, hierarchy); 29 | init(); 30 | } 31 | 32 | public SingleImageView(Context context) { 33 | super(context); 34 | init(); 35 | } 36 | 37 | public SingleImageView(Context context, AttributeSet attrs) { 38 | this(context, attrs, 0); 39 | } 40 | 41 | public SingleImageView(Context context, AttributeSet attrs, int defStyle) { 42 | super(context, attrs, defStyle); 43 | 44 | init(); 45 | } 46 | 47 | private void init() { 48 | setOnClickListener(this); 49 | mImage = new SquareImage(); 50 | } 51 | 52 | public void doUpLoadPhotoClick() { 53 | doUpLoadPhotoClick(1, 1); 54 | } 55 | 56 | public void doUpLoadPhotoClick(final int aspectRatioX, final int aspectRatioY) { 57 | new AlertDialog.Builder(getContext()) 58 | .setItems(new String[]{getContext().getString(R.string.take_photo), 59 | getContext().getString(R.string.select_images)}, 60 | new DialogInterface.OnClickListener() { 61 | @Override 62 | public void onClick(DialogInterface dialog, int which) { 63 | if (which == 0) { 64 | doTakePhoto(aspectRatioX, aspectRatioY); 65 | } else { 66 | doAlbum(aspectRatioX, aspectRatioY); 67 | } 68 | } 69 | }) 70 | .show(); 71 | } 72 | 73 | public void doTakePhoto(int aspectRatioX, int aspectRatioY) { 74 | NavigatorImage.INSTANCE.startAvatarAlbumActivity(getContext(), getId(), AlbumActivity.Companion.getTAKE_PHOTO(), aspectRatioX, aspectRatioY); 75 | } 76 | 77 | public void doAlbum(int aspectRatioX, int aspectRatioY) { 78 | NavigatorImage.INSTANCE.startAvatarAlbumActivity(getContext(), getId(), AlbumActivity.Companion.getALBUM(), aspectRatioX, aspectRatioY); 79 | } 80 | 81 | @Override 82 | public void onClick(View v) { 83 | doUpLoadPhotoClick(); 84 | } 85 | 86 | public void onParentResult(int requestCode, Intent data) { 87 | if (data == null || data.getIntExtra(NavigatorImage.EXTRA_IMAGE_GROUP_ID, 0) != getId()) return; 88 | List images = (List) data.getSerializableExtra(NavigatorImage.EXTRA_PHOTOS_URL); 89 | if (requestCode == NavigatorImage.RESULT_SELECT_PHOTOS && null != images) { 90 | refreshLocalImage(images.get(0).url); 91 | } 92 | } 93 | 94 | private void refreshLocalImage(String url) { 95 | mImage.localUrl = url; 96 | updateView(); 97 | } 98 | 99 | private void updateView() { 100 | if (getHeight() == 0) { 101 | post(new Runnable() { 102 | @Override 103 | public void run() { 104 | updateView(); 105 | } 106 | }); 107 | return; 108 | } 109 | if (mImage.localUrl != null) { 110 | ImageGroupDisplayHelper.displayImageLocal(this, mImage.localUrl, getWidth(), getHeight()); 111 | } else if (mImage.interNetUrl != null) { 112 | ImageGroupDisplayHelper.displayImage(this, mImage.interNetUrl, mPlaceholderDrawable, getWidth(), getHeight()); 113 | } else { 114 | setImageResource(mPlaceholderDrawable); 115 | } 116 | } 117 | 118 | public void updateImage(SquareImage squareImage) { 119 | mImage = squareImage; 120 | updateView(); 121 | } 122 | 123 | public String getLocalUrl() { 124 | if (mImage == null) return null; 125 | return mImage.localUrl; 126 | } 127 | 128 | @NonNull 129 | private String getPhotoKey() { 130 | return "image_" + System.currentTimeMillis(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /imagegroupview/src/main/java/com/loopeer/android/librarys/imagegroupview/view/SquareImageView.java: -------------------------------------------------------------------------------- 1 | package com.loopeer.android.librarys.imagegroupview.view; 2 | 3 | import android.content.Context; 4 | import android.support.v4.content.ContextCompat; 5 | import android.text.TextUtils; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | 9 | import com.facebook.drawee.drawable.ScalingUtils; 10 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 11 | import com.facebook.drawee.generic.RoundingParams; 12 | import com.facebook.drawee.view.SimpleDraweeView; 13 | import com.loopeer.android.librarys.imagegroupview.utils.ImageGroupDisplayHelper; 14 | import com.loopeer.android.librarys.imagegroupview.R; 15 | import com.loopeer.android.librarys.imagegroupview.model.SquareImage; 16 | 17 | public class SquareImageView extends SimpleDraweeView implements View.OnClickListener{ 18 | 19 | private String mLocalUrl; 20 | private String mUploadKey; 21 | private String mInternetUrl; 22 | private int placeholderDrawable; 23 | private int width; 24 | private boolean mClickUpload = true; 25 | 26 | public SquareImageView(Context context) { 27 | this(context, null); 28 | } 29 | 30 | public SquareImageView(Context context, AttributeSet attrs) { 31 | this(context, attrs, 0); 32 | } 33 | 34 | public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) { 35 | super(context, attrs, defStyleAttr); 36 | init(); 37 | } 38 | 39 | private void init() { 40 | placeholderDrawable = R.drawable.ic_image_default; 41 | setScaleType(ScaleType.CENTER_CROP); 42 | setClickable(mClickUpload); 43 | setLongClickable(true); 44 | setOnClickListener(this); 45 | GenericDraweeHierarchyBuilder builder1 = new GenericDraweeHierarchyBuilder(getContext().getResources()); 46 | builder1.setPlaceholderImage(ContextCompat.getDrawable(getContext(), placeholderDrawable), ScalingUtils.ScaleType.CENTER_CROP); 47 | getControllerBuilder().build().setHierarchy(builder1.build()); 48 | } 49 | 50 | public void setWidthByParent(int widthByParent) { 51 | width = widthByParent; 52 | } 53 | 54 | public void setPlaceholderDrawable(int src) { 55 | placeholderDrawable = src; 56 | getHierarchy().setPlaceholderImage(placeholderDrawable); 57 | } 58 | 59 | @Override 60 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 61 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 62 | setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); 63 | int childWidthSize = getMeasuredWidth(); 64 | heightMeasureSpec = widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); 65 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 66 | } 67 | 68 | public void setLocalUrl(final String localUrl) { 69 | if (!TextUtils.isEmpty(mInternetUrl)) mInternetUrl = null; 70 | if (getHeight() == 0) { 71 | post(new Runnable() { 72 | @Override 73 | public void run() { 74 | setLocalUrl(localUrl); 75 | } 76 | }); 77 | return; 78 | } 79 | mLocalUrl = localUrl; 80 | ImageGroupDisplayHelper.displayImageLocal(this, mLocalUrl, getWidth(), getHeight()); 81 | } 82 | 83 | @SuppressWarnings("unused") 84 | public void setInternetUrl(String internetUrl) { 85 | mInternetUrl = internetUrl; 86 | } 87 | 88 | @SuppressWarnings("unused") 89 | public void setUploadKey(String key) { 90 | mUploadKey = key; 91 | } 92 | 93 | public String getUploadImageKey() { 94 | return mUploadKey; 95 | } 96 | 97 | public String getLocalUrl() { 98 | return mLocalUrl; 99 | } 100 | public String getImageLocalUrl() { 101 | return mLocalUrl; 102 | } 103 | 104 | public String getInternetUrl() { 105 | return mInternetUrl; 106 | } 107 | 108 | public void setInternetData(final String netUrl) { 109 | mInternetUrl = netUrl; 110 | mLocalUrl = null; 111 | if (netUrl == null) { 112 | setImageResource(placeholderDrawable); 113 | return; 114 | } 115 | if (getHeight() == 0) { 116 | post(new Runnable() { 117 | @Override 118 | public void run() { 119 | setInternetData(netUrl); 120 | } 121 | }); 122 | return; 123 | } 124 | ImageGroupDisplayHelper.displayImage(this, mInternetUrl, placeholderDrawable, getWidth(), getHeight()); 125 | } 126 | 127 | public void setImageData(SquareImage squareImage) { 128 | if (squareImage.localUrl != null) setLocalUrl(squareImage.localUrl); 129 | if (squareImage.interNetUrl != null) setInternetData(squareImage.interNetUrl); 130 | if (squareImage.urlKey != null) setUploadKey(squareImage.urlKey); 131 | } 132 | 133 | @SuppressWarnings("unused") 134 | public void setClickAble (boolean able) { 135 | mClickUpload = able; 136 | } 137 | 138 | @Override 139 | public void onClick(View v) { 140 | if (mClickUpload) { 141 | 142 | } else { 143 | 144 | } 145 | } 146 | 147 | public View getSquareImage() { 148 | return null; 149 | } 150 | 151 | public void setRoundAsCircle(boolean flag) { 152 | if (!flag) return; 153 | RoundingParams roundingParams = RoundingParams.fromCornersRadius(5f); 154 | roundingParams.setRoundAsCircle(flag); 155 | getHierarchy().setRoundingParams(roundingParams); 156 | 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/anim/pophidden_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/anim/popshow_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xhdpi/ic_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xhdpi/ic_delete.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xhdpi/ic_image_delete_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xhdpi/ic_image_delete_icon.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xhdpi/ic_photo_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xhdpi/ic_photo_default.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xxhdpi/ic_arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xxhdpi/ic_arrow_right.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xxhdpi/ic_image_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xxhdpi/ic_image_default.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_camera.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_folder_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_folder_check.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_selected.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/imagegroupview/src/main/res/drawable-xxhdpi/ic_image_group_unselected.png -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable/image_group_button_background_primary_corner_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/drawable/selected_image_check_box.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/activity_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/activity_image_picker.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 19 | 20 | 30 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/activity_image_switcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 17 | 18 | 26 | 27 | 35 | 36 | 45 | 46 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/activity_images.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 22 | 23 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/activity_scale_image.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/dialog_fragment_get_photo.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 23 | 24 | 25 | 26 | 32 | 33 | 40 | 41 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/drag_recycle.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 30 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/fragment_scale_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 25 | 26 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/item_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/list_item_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 19 | 20 | 26 | 27 | 35 | 36 | 45 | 46 | 47 | 48 | 55 | 56 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/list_item_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/list_item_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 27 | 28 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/view_menu_submit.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 21 | 22 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/view_popup_folder.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 28 | 29 | 30 | 31 | 37 | 38 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/layout/view_recycler_image_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 23 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/menu/menu_image_group_submit.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values-en/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Images 3 | Album 4 | Camera 5 | All 6 | Submit 7 | Submit(%1$d/%2$d) 8 | Submit(%1$d) 9 | Delete this Photo? 10 | Delete 11 | Only four photos can add 12 | Cancel 13 | 14 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 图片 3 | 相册 4 | 相机 5 | 所有照片 6 | 提交 7 | 提交(%1$d/%2$d) 8 | 提交(%1$d) 9 | 确认删除这张照片? 10 | 删除 11 | 最多只能添加%d张图片哦 12 | 取消 13 | 14 | 15 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #212121 5 | #000000 6 | 7 | #DDDDDD 8 | @color/button_disable 9 | 10 | #CBCBCB 11 | #CCCCCC 12 | #44000000 13 | #dcdcdc 14 | 15 | #55000000 16 | 17 | #FF222222 18 | #00222222 19 | 20 | @android:color/white 21 | #04b00f 22 | #FF1D6C22 23 | 24 | #aaDC143C 25 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 12dp 6 | 12dp 7 | 8 | 8dp 9 | 4dp 10 | 94dp 11 | 48dp 12 | 13 | 14dp 14 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ImageGroupView 3 | 4 | Images 5 | Album 6 | Camera 7 | All 8 | Submit 9 | Submit(%1$d/%2$d) 10 | Submit(%1$d) 11 | 12 | Please set the permission in the app settings 13 | 14 | com.loopeer.android.librarys.imagegroupview 15 | imagegroupview://switcher 16 | imagegroupview://album 17 | 拖动到此处删除 18 | 19 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /imagegroupview/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /screenshot/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/screenshot/screenshot.gif -------------------------------------------------------------------------------- /screenshot/screenshot_select_animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/screenshot/screenshot_select_animation.gif -------------------------------------------------------------------------------- /screenshot/screenshot_select_photo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/screenshot/screenshot_select_photo.gif -------------------------------------------------------------------------------- /screenshot/screenshot_witcher.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopeer/ImageGroupView/9cc91b8688c093931ac1acebe8debdc4eb3c4a02/screenshot/screenshot_witcher.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':imagegroupview' 2 | -------------------------------------------------------------------------------- /upload.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "\033[1;32mBuild Start \033[0m" 4 | ./gradlew :imagegroupview:build 5 | echo "\033[1;32mInstall Start \033[0m" 6 | ./gradlew :imagegroupview:install 7 | echo "\033[1;32mBintray Upload Start \033[0m" 8 | ./gradlew :imagegroupview:bintrayUpload 9 | --------------------------------------------------------------------------------