├── .idea ├── .name ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── modules.xml ├── runConfigurations.xml ├── compiler.xml ├── gradle.xml └── misc.xml ├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── styles.xml │ │ │ │ ├── dimens.xml │ │ │ │ └── colors.xml │ │ │ ├── drawable-xhdpi │ │ │ │ ├── s_jr_ico.png │ │ │ │ ├── shop_ico.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── topbar_up.png │ │ │ │ ├── checkbox_checked.png │ │ │ │ ├── checkbox_normal.png │ │ │ │ └── topbar_background.9.png │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable │ │ │ │ ├── check_box_bg.xml │ │ │ │ ├── text_angle.xml │ │ │ │ ├── list_selector.xml │ │ │ │ ├── selector_slider_holder.xml │ │ │ │ ├── text_angle_gray.xml │ │ │ │ └── text_angle_right.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ └── layout │ │ │ │ ├── slide_view_merge.xml │ │ │ │ ├── item_shopcart_group.xml │ │ │ │ ├── activity_main.xml │ │ │ │ └── item_shopcart_product.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── zxj │ │ │ │ └── shoppingcart │ │ │ │ ├── bean │ │ │ │ ├── GroupInfo.java │ │ │ │ ├── BaseInfo.java │ │ │ │ └── ProductInfo.java │ │ │ │ ├── widget │ │ │ │ ├── SlideView.java │ │ │ │ └── SuperExpandableListView.java │ │ │ │ ├── adapter │ │ │ │ └── ShopcartExpandableListViewAdapter.java │ │ │ │ └── MainActivity.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── zxj │ │ │ └── shoppingcart │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── zxj │ │ └── shoppingcart │ │ └── ApplicationTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── GIF.gif ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── gradlew.bat ├── gradlew └── README.md /.idea/.name: -------------------------------------------------------------------------------- 1 | ShoppingCart -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /GIF.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/GIF.gif -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ShoppingCart 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/s_jr_ico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/drawable-xhdpi/s_jr_ico.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/shop_ico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/drawable-xhdpi/shop_ico.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/topbar_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/drawable-xhdpi/topbar_up.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/checkbox_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/drawable-xhdpi/checkbox_checked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/checkbox_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/drawable-xhdpi/checkbox_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/topbar_background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itzuo/ShoppingCart/HEAD/app/src/main/res/drawable-xhdpi/topbar_background.9.png -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/check_box_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/text_angle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/zxj/shoppingcart/bean/GroupInfo.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart.bean; 2 | 3 | public class GroupInfo extends BaseInfo 4 | { 5 | public GroupInfo() 6 | { 7 | super(); 8 | } 9 | 10 | public GroupInfo(String id, String name) 11 | { 12 | super(id, name); 13 | // TODO Auto-generated constructor stub 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/test/java/com/zxj/shoppingcart/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zxj/shoppingcart/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_slider_holder.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/text_angle_gray.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/text_angle_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /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 /home/xzj/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/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.zxj.shoppingcart" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.0.0' 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | 7 | 8sp 8 | 10sp 9 | 12sp 10 | 14sp 11 | 16sp 12 | 18sp 13 | 20sp 14 | 22sp 15 | 24sp 16 | 26sp 17 | 28sp 18 | 90dp 19 | 20 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /app/src/main/java/com/zxj/shoppingcart/bean/BaseInfo.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart.bean; 2 | 3 | 4 | public class BaseInfo 5 | { 6 | protected String Id; 7 | protected String name; 8 | protected boolean isChoosed; 9 | 10 | public BaseInfo() 11 | { 12 | super(); 13 | } 14 | 15 | public BaseInfo(String id, String name) 16 | { 17 | super(); 18 | Id = id; 19 | this.name = name; 20 | 21 | } 22 | 23 | public String getId() 24 | { 25 | return Id; 26 | } 27 | 28 | public void setId(String id) 29 | { 30 | Id = id; 31 | } 32 | 33 | public String getName() 34 | { 35 | return name; 36 | } 37 | 38 | public void setName(String name) 39 | { 40 | this.name = name; 41 | } 42 | 43 | public boolean isChoosed() 44 | { 45 | return isChoosed; 46 | } 47 | 48 | public void setChoosed(boolean isChoosed) 49 | { 50 | this.isChoosed = isChoosed; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/zxj/shoppingcart/bean/ProductInfo.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart.bean; 2 | 3 | 4 | public class ProductInfo extends BaseInfo 5 | { 6 | private String imageUrl; 7 | private String desc; 8 | private double price; 9 | private int count; 10 | private int position;// 绝对位置,只在ListView构造的购物车中,在删除时有效 11 | 12 | public ProductInfo() 13 | { 14 | super(); 15 | } 16 | 17 | public ProductInfo(String id, String name, String imageUrl, String desc, double price, int count) 18 | { 19 | 20 | super.Id = id; 21 | super.name = name; 22 | this.imageUrl = imageUrl; 23 | this.desc = desc; 24 | this.price = price; 25 | this.count = count; 26 | 27 | } 28 | 29 | public String getImageUrl() 30 | { 31 | return imageUrl; 32 | } 33 | 34 | public void setImageUrl(String imageUrl) 35 | { 36 | this.imageUrl = imageUrl; 37 | } 38 | 39 | public String getDesc() 40 | { 41 | return desc; 42 | } 43 | 44 | public void setDesc(String desc) 45 | { 46 | this.desc = desc; 47 | } 48 | 49 | public int getCount() 50 | { 51 | return count; 52 | } 53 | 54 | public void setCount(int count) 55 | { 56 | this.count = count; 57 | } 58 | 59 | public double getPrice() 60 | { 61 | return price; 62 | } 63 | 64 | public void setPrice(double price) 65 | { 66 | this.price = price; 67 | } 68 | 69 | public int getPosition() 70 | { 71 | return position; 72 | } 73 | 74 | public void setPosition(int position) 75 | { 76 | this.position = position; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/slide_view_merge.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 18 | 19 | 29 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_shopcart_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 28 | 29 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 12 | 13 | 18 | 19 | 27 | 28 | 37 | 38 | 50 | 51 | 52 | 53 | 60 | 61 | 65 | 66 | 72 | 73 | 87 | 88 | 95 | 96 | 104 | 105 | 106 | 116 | 117 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /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/src/main/java/com/zxj/shoppingcart/widget/SlideView.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.util.AttributeSet; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.widget.LinearLayout; 11 | import android.widget.Scroller; 12 | import android.widget.TextView; 13 | 14 | import com.zxj.shoppingcart.R; 15 | 16 | /** 17 | * @描述: 侧滑删除组件 18 | * @项目名: ShoppingCart 19 | * @包名: com.zxj.shoppingcart.widget 20 | * @类名: SlideView 21 | * @作者: zuojie 22 | * @创建时间: 16-8-22 下午2:14 23 | */ 24 | public class SlideView extends LinearLayout { 25 | public static final String TAG = "SlideView"; 26 | 27 | private static final int TAN = 2; 28 | private int mHolderWidth = 90; 29 | private float mLastX = 0; 30 | private float mLastY = 0; 31 | private LinearLayout mViewContent; 32 | private Scroller mScroller; 33 | private Context mContext; 34 | private Resources mResources; 35 | 36 | public TextView getBack() { 37 | return back; 38 | } 39 | 40 | private TextView back; 41 | 42 | public SlideView(Context context, Resources resources, View content) { 43 | super(context); 44 | initView(context, resources, content); 45 | } 46 | 47 | 48 | public SlideView(Context context, AttributeSet attrs) { 49 | super(context, attrs); 50 | // TODO Auto-generated constructor stub 51 | initView(context, context.getResources(), null); 52 | } 53 | 54 | public SlideView(Context context) { 55 | super(context); 56 | // TODO Auto-generated constructor stub 57 | initView(context, context.getResources(), null); 58 | } 59 | private void initView(Context context, Resources resources, View content) { 60 | // TODO Auto-generated method stub 61 | setOrientation(LinearLayout.HORIZONTAL); 62 | this.mContext = context; 63 | this.mResources = resources; 64 | Log.i(TAG, "---1---"); 65 | mScroller = new Scroller(context); 66 | Log.i(TAG, "---2---"); 67 | View view = LayoutInflater.from(context).inflate(resources.getLayout(R.layout.slide_view_merge), this); 68 | Log.i(TAG, "---3---"); 69 | // view.findViewById(R.id.holder).setBackground(resources.getDrawable(R.drawable.selector_slider_holder)); 70 | Log.i(TAG, "---4---"); 71 | // shenhe = (TextView) view.findViewById(R.id.shenhe); 72 | // back = (TextView) findViewById(R.id.back); 73 | // back.setCompoundDrawablesWithIntrinsicBounds(null, resources.getDrawable(R.drawable.back), null, null); 74 | // back.setOnClickListener(this); 75 | // shenhe.setOnClickListener(this); 76 | mViewContent = (LinearLayout) view.findViewById(R.id.view_content); 77 | // mHolderWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources().getDisplayMetrics())); 78 | mHolderWidth = getResources().getDimensionPixelSize(R.dimen.width_); 79 | if(content!=null){ 80 | mViewContent.addView(content); 81 | } 82 | } 83 | 84 | @Override 85 | public boolean onTouchEvent(MotionEvent event) { 86 | switch (event.getAction()) { 87 | case MotionEvent.ACTION_MOVE: 88 | float x = event.getX(); 89 | float y = event.getY(); 90 | float deltaX = x - mLastX; 91 | float deltaY = y - mLastY; 92 | mLastX = x; 93 | mLastY = y; 94 | if(Math.abs(deltaX) mHolderWidth){ 102 | newScrollX = mHolderWidth; 103 | } 104 | this.scrollTo((int)newScrollX, 0); 105 | } 106 | break; 107 | } 108 | return super.onTouchEvent(event); 109 | } 110 | 111 | private void smoothScrollTo(int destX, int destY) { 112 | int scrollX = getScrollX(); 113 | int delta = destX - scrollX; 114 | mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3); 115 | invalidate(); 116 | } 117 | 118 | @Override 119 | public void computeScroll() { 120 | if (mScroller.computeScrollOffset()) { 121 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 122 | postInvalidate(); 123 | } 124 | } 125 | /** 126 | * 获取view是需要重置缓存状态 127 | */ 128 | public void shrink() { 129 | int offset = getScrollX(); 130 | if (offset == 0) { 131 | return; 132 | } 133 | scrollTo(0, 0); 134 | } 135 | 136 | public void setContentView(View view) { 137 | if (mViewContent != null) { 138 | mViewContent.addView(view); 139 | } 140 | } 141 | 142 | public void reset() { 143 | int offset = getScrollX(); 144 | if (offset == 0) { 145 | return; 146 | } 147 | smoothScrollTo(0, 0); 148 | } 149 | 150 | public void adjust(boolean left) { 151 | int offset = getScrollX(); 152 | if (offset == 0) { 153 | return; 154 | } 155 | if (offset < 20) { 156 | this.smoothScrollTo(0, 0); 157 | } else if (offset < mHolderWidth - 20) { 158 | if (left) { 159 | this.smoothScrollTo(mHolderWidth, 0); 160 | } else { 161 | this.smoothScrollTo(0, 0); 162 | } 163 | } else { 164 | this.smoothScrollTo(mHolderWidth, 0); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_shopcart_product.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 17 | 18 | 32 | 33 | 41 | 42 | 46 | 47 | 58 | 59 | 65 | 66 | 76 | 77 | 89 | 90 | 97 | 98 | 107 | 108 | 118 | 119 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/zxj/shoppingcart/widget/SuperExpandableListView.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.MotionEvent; 7 | import android.view.ViewConfiguration; 8 | import android.view.ViewGroup; 9 | import android.widget.ExpandableListView; 10 | 11 | import com.zxj.shoppingcart.R; 12 | 13 | /** 14 | * @描述: 自定义的ExpandableListView,处理滑动冲突 15 | * @项目名: ShoppingCart 16 | * @包名: com.zxj.shoppingcart.widget 17 | * @类名: SuperExpandableListView 18 | * @作者: zuojie 19 | * @创建时间: 16-8-22 下午2:32 20 | */ 21 | public class SuperExpandableListView extends ExpandableListView { 22 | 23 | private static final String TAG = SuperExpandableListView.class.getCanonicalName(); 24 | /** 25 | * 用户滑动最小距离 26 | */ 27 | private int touchSlop; 28 | /** 29 | * 是否相应滑动 30 | */ 31 | private boolean isSliding; 32 | /** 33 | * 手指按下时x坐标 34 | */ 35 | private int xDown; 36 | /** 37 | * 手指按下时的y坐标 38 | */ 39 | private int yDown; 40 | /** 41 | * 手指移动时的x坐标 42 | */ 43 | private int xMove; 44 | /** 45 | * 手指移动时的y坐标 46 | */ 47 | private int yMove; 48 | 49 | boolean isChild; 50 | 51 | private LayoutInflater mInflater; 52 | 53 | private ViewGroup itemLayout; 54 | 55 | 56 | private SlideView mFocusedItemView; 57 | 58 | 59 | /** 60 | * 为删除按钮提供一个回调接口 61 | */ 62 | private ButtonClickListener mListener; 63 | /** 64 | * 当前手指触摸的View 65 | */ 66 | 67 | /** 68 | * 当前手指触摸的位置 69 | */ 70 | private int mCurrentViewPos = -1; 71 | 72 | 73 | public SuperExpandableListView(Context context, AttributeSet attrs, 74 | int defStyle) { 75 | super(context, attrs, defStyle); 76 | initData(context); 77 | // TODO Auto-generated constructor stub 78 | } 79 | 80 | public SuperExpandableListView(Context context, AttributeSet attrs) { 81 | super(context, attrs); 82 | // TODO Auto-generated constructor stub 83 | initData(context); 84 | } 85 | 86 | public SuperExpandableListView(Context context) { 87 | super(context); 88 | // TODO Auto-generated constructor stub 89 | initData(context); 90 | } 91 | 92 | private void initData(Context context) { 93 | mInflater = LayoutInflater.from(context); 94 | touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 95 | } 96 | 97 | @Override 98 | public boolean dispatchTouchEvent(MotionEvent ev) { 99 | int action = ev.getAction(); 100 | int x = (int) ev.getX(); 101 | int y = (int) ev.getY(); 102 | switch (action) { 103 | case MotionEvent.ACTION_DOWN: 104 | // isSliding = false; 105 | // if(isSliding){ 106 | // a 107 | // } 108 | xDown = x; 109 | yDown = y; 110 | // 获得当前手指按下时的item的位置 111 | int position = pointToPosition(xDown, yDown); 112 | if (mCurrentViewPos != position || isSliding) { 113 | mCurrentViewPos = position; 114 | isSliding = false; 115 | if (mFocusedItemView != null) { 116 | mFocusedItemView.reset(); 117 | } 118 | } 119 | // 获得当前手指按下时的item 120 | itemLayout = (ViewGroup) getChildAt(mCurrentViewPos - getFirstVisiblePosition()); 121 | if (itemLayout != null) { 122 | int id = itemLayout.getId(); 123 | if (id == R.id.SwipeMenuExpandableListView) { 124 | isChild = false; 125 | } else { 126 | isChild = true; 127 | } 128 | /*if(itemLayout instanceof RelativeLayout){ 129 | isChild = false; 130 | }else{ 131 | isChild = true; 132 | }*/ 133 | } 134 | break; 135 | case MotionEvent.ACTION_MOVE: 136 | xMove = x; 137 | yMove = y; 138 | int dx = xMove - xDown; 139 | int dy = yMove - yDown; 140 | /** 141 | * 判断是否是从右到左的滑动 142 | */ 143 | if (xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop && isChild) { 144 | // Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx + " , dy = " + dy); 145 | isSliding = true; 146 | } 147 | break; 148 | } 149 | return super.dispatchTouchEvent(ev); 150 | } 151 | 152 | @Override 153 | public boolean onTouchEvent(MotionEvent ev) { 154 | int action = ev.getAction(); 155 | int x = (int) ev.getX(); 156 | int y = (int) ev.getY(); 157 | /** 158 | * 如果是从右到左的滑动才相应 159 | */ 160 | if (isSliding) { 161 | switch (action) { 162 | case MotionEvent.ACTION_MOVE: 163 | if (mCurrentViewPos != -1) { 164 | if (Math.abs(yDown - y) < 30 && Math.abs(xDown - x) > 20) { 165 | int first = this.getFirstVisiblePosition(); 166 | int index = mCurrentViewPos - first; 167 | mFocusedItemView = (SlideView) getChildAt(index); 168 | mFocusedItemView.onTouchEvent(ev); 169 | return true; 170 | } 171 | } 172 | 173 | break; 174 | case MotionEvent.ACTION_UP: 175 | isChild = false; 176 | if (isSliding) { 177 | // isSliding = false; 178 | if (mFocusedItemView != null) { 179 | mFocusedItemView.adjust(xDown - x > 0); 180 | return true; 181 | } 182 | } 183 | } 184 | // 相应滑动期间屏幕itemClick事件,避免发生冲突 185 | return true; 186 | } 187 | 188 | return super.onTouchEvent(ev); 189 | } 190 | 191 | 192 | public void setButtonClickListener(ButtonClickListener listener) { 193 | mListener = listener; 194 | } 195 | 196 | interface ButtonClickListener { 197 | public void clickHappend(int position); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /app/src/main/java/com/zxj/shoppingcart/adapter/ShopcartExpandableListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.view.View.OnClickListener; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseExpandableListAdapter; 8 | import android.widget.CheckBox; 9 | import android.widget.TextView; 10 | 11 | import com.zxj.shoppingcart.R; 12 | import com.zxj.shoppingcart.bean.GroupInfo; 13 | import com.zxj.shoppingcart.bean.ProductInfo; 14 | import com.zxj.shoppingcart.widget.SlideView; 15 | 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | 20 | public class ShopcartExpandableListViewAdapter extends BaseExpandableListAdapter { 21 | private List groups; 22 | private Map> children; 23 | private Context context; 24 | //HashMap groupMap = new HashMap(); 25 | //HashMap childrenMap = new HashMap(); 26 | private CheckInterface checkInterface; 27 | private ModifyCountInterface modifyCountInterface; 28 | 29 | /** 30 | * 构造函数 31 | * 32 | * @param groups 组元素列表 33 | * @param children 子元素列表 34 | * @param context 35 | */ 36 | public ShopcartExpandableListViewAdapter(List groups, Map> children, Context context) { 37 | super(); 38 | this.groups = groups; 39 | this.children = children; 40 | this.context = context; 41 | } 42 | 43 | public void setCheckInterface(CheckInterface checkInterface) { 44 | this.checkInterface = checkInterface; 45 | } 46 | 47 | public void setModifyCountInterface(ModifyCountInterface modifyCountInterface) { 48 | this.modifyCountInterface = modifyCountInterface; 49 | } 50 | 51 | @Override 52 | public int getGroupCount() { 53 | return groups.size(); 54 | } 55 | 56 | @Override 57 | public int getChildrenCount(int groupPosition) { 58 | String groupId = groups.get(groupPosition).getId(); 59 | return children.get(groupId).size(); 60 | } 61 | 62 | @Override 63 | public Object getGroup(int groupPosition) { 64 | return groups.get(groupPosition); 65 | } 66 | 67 | @Override 68 | public Object getChild(int groupPosition, int childPosition) { 69 | List childs = children.get(groups.get(groupPosition).getId()); 70 | 71 | return childs.get(childPosition); 72 | } 73 | 74 | @Override 75 | public long getGroupId(int groupPosition) { 76 | return groupPosition; 77 | } 78 | 79 | @Override 80 | public long getChildId(int groupPosition, int childPosition) { 81 | return childPosition; 82 | } 83 | 84 | @Override 85 | public boolean hasStableIds() { 86 | return false; 87 | } 88 | 89 | @Override 90 | public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 91 | GroupHolder gholder; 92 | if (convertView == null) { 93 | gholder = new GroupHolder(); 94 | convertView = View.inflate(context, R.layout.item_shopcart_group, null); 95 | gholder.cb_check = (CheckBox) convertView.findViewById(R.id.determine_chekbox); 96 | gholder.tv_group_name = (TextView) convertView.findViewById(R.id.tv_source_name); 97 | //groupMap.put(groupPosition, convertView); 98 | convertView.setTag(gholder); 99 | } else { 100 | // convertView = groupMap.get(groupPosition); 101 | gholder = (GroupHolder) convertView.getTag(); 102 | } 103 | final GroupInfo group = (GroupInfo) getGroup(groupPosition); 104 | if (group != null) { 105 | gholder.tv_group_name.setText(group.getName()); 106 | gholder.cb_check.setOnClickListener(new OnClickListener() { 107 | @Override 108 | public void onClick(View v) 109 | 110 | { 111 | group.setChoosed(((CheckBox) v).isChecked()); 112 | checkInterface.checkGroup(groupPosition, ((CheckBox) v).isChecked());// 暴露组选接口 113 | } 114 | }); 115 | gholder.cb_check.setChecked(group.isChoosed()); 116 | } 117 | return convertView; 118 | } 119 | 120 | @Override 121 | public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { 122 | SlideView slideView = null; 123 | final ChildHolder cholder; 124 | if (convertView == null) { 125 | cholder = new ChildHolder(); 126 | View view = View.inflate(context, R.layout.item_shopcart_product, null); 127 | slideView = new SlideView(context, context.getResources(), view); 128 | convertView = slideView; 129 | cholder.cb_check = (CheckBox) convertView.findViewById(R.id.check_box); 130 | 131 | cholder.tv_product_desc = (TextView) convertView.findViewById(R.id.tv_intro); 132 | cholder.tv_price = (TextView) convertView.findViewById(R.id.tv_price); 133 | cholder.iv_increase = (TextView) convertView.findViewById(R.id.tv_add); 134 | cholder.iv_decrease = (TextView) convertView.findViewById(R.id.tv_reduce); 135 | cholder.tv_count = (TextView) convertView.findViewById(R.id.tv_num); 136 | 137 | cholder.tv_delete = (TextView) convertView.findViewById(R.id.back); 138 | // childrenMap.put(groupPosition, convertView); 139 | convertView.setTag(cholder); 140 | } else { 141 | // convertView = childrenMap.get(groupPosition); 142 | cholder = (ChildHolder) convertView.getTag(); 143 | } 144 | final ProductInfo product = (ProductInfo) getChild(groupPosition, childPosition); 145 | 146 | if (product != null) { 147 | 148 | cholder.tv_product_desc.setText(product.getDesc()); 149 | cholder.tv_price.setText("¥" + product.getPrice() + ""); 150 | cholder.tv_count.setText(product.getCount() + ""); 151 | cholder.cb_check.setChecked(product.isChoosed()); 152 | cholder.cb_check.setOnClickListener(new OnClickListener() { 153 | @Override 154 | public void onClick(View v) { 155 | product.setChoosed(((CheckBox) v).isChecked()); 156 | cholder.cb_check.setChecked(((CheckBox) v).isChecked()); 157 | checkInterface.checkChild(groupPosition, childPosition, ((CheckBox) v).isChecked());// 暴露子选接口 158 | } 159 | }); 160 | cholder.iv_increase.setOnClickListener(new OnClickListener() { 161 | @Override 162 | public void onClick(View v) { 163 | modifyCountInterface.doIncrease(groupPosition, childPosition, cholder.tv_count, cholder.cb_check.isChecked());// 暴露增加接口 164 | } 165 | }); 166 | cholder.iv_decrease.setOnClickListener(new OnClickListener() { 167 | @Override 168 | public void onClick(View v) { 169 | modifyCountInterface.doDecrease(groupPosition, childPosition, cholder.tv_count, cholder.cb_check.isChecked());// 暴露删减接口 170 | } 171 | }); 172 | } 173 | cholder.tv_delete.setOnClickListener(new OnClickListener() { 174 | 175 | @Override 176 | public void onClick(View v) { 177 | List childs = children.get(groups.get(groupPosition).getId()); 178 | childs.remove(childPosition); 179 | if(childs.size() ==0){//child没有了,group也就没有了 180 | groups.remove(groupPosition); 181 | } 182 | notifyDataSetChanged(); 183 | } 184 | }); 185 | return convertView; 186 | } 187 | 188 | @Override 189 | public boolean isChildSelectable(int groupPosition, int childPosition) { 190 | return false; 191 | } 192 | 193 | /** 194 | * 组元素绑定器 195 | */ 196 | private class GroupHolder { 197 | CheckBox cb_check; 198 | TextView tv_group_name; 199 | } 200 | 201 | /** 202 | * 子元素绑定器 203 | */ 204 | private class ChildHolder { 205 | CheckBox cb_check; 206 | 207 | TextView tv_product_name; 208 | TextView tv_product_desc; 209 | TextView tv_price; 210 | TextView iv_increase; 211 | TextView tv_count; 212 | TextView iv_decrease; 213 | TextView tv_delete; 214 | } 215 | 216 | /** 217 | * 复选框接口 218 | */ 219 | public interface CheckInterface { 220 | /** 221 | * 组选框状态改变触发的事件 222 | * 223 | * @param groupPosition 组元素位置 224 | * @param isChecked 组元素选中与否 225 | */ 226 | public void checkGroup(int groupPosition, boolean isChecked); 227 | 228 | /** 229 | * 子选框状态改变时触发的事件 230 | * 231 | * @param groupPosition 组元素位置 232 | * @param childPosition 子元素位置 233 | * @param isChecked 子元素选中与否 234 | */ 235 | public void checkChild(int groupPosition, int childPosition, boolean isChecked); 236 | } 237 | 238 | /** 239 | * 改变数量的接口 240 | */ 241 | public interface ModifyCountInterface { 242 | /** 243 | * 增加操作 244 | * 245 | * @param groupPosition 组元素位置 246 | * @param childPosition 子元素位置 247 | * @param showCountView 用于展示变化后数量的View 248 | * @param isChecked 子元素选中与否 249 | */ 250 | public void doIncrease(int groupPosition, int childPosition, View showCountView, boolean isChecked); 251 | 252 | /** 253 | * 删减操作 254 | * 255 | * @param groupPosition 组元素位置 256 | * @param childPosition 子元素位置 257 | * @param showCountView 用于展示变化后数量的View 258 | * @param isChecked 子元素选中与否 259 | */ 260 | public void doDecrease(int groupPosition, int childPosition, View showCountView, boolean isChecked); 261 | } 262 | 263 | } 264 | -------------------------------------------------------------------------------- /app/src/main/java/com/zxj/shoppingcart/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zxj.shoppingcart; 2 | 3 | import android.content.Context; 4 | import android.content.DialogInterface; 5 | import android.support.v7.app.AlertDialog; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.view.Window; 10 | import android.widget.CheckBox; 11 | import android.widget.TextView; 12 | import android.widget.Toast; 13 | 14 | import com.zxj.shoppingcart.adapter.ShopcartExpandableListViewAdapter; 15 | import com.zxj.shoppingcart.bean.GroupInfo; 16 | import com.zxj.shoppingcart.bean.ProductInfo; 17 | import com.zxj.shoppingcart.widget.SuperExpandableListView; 18 | 19 | import java.util.ArrayList; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | 24 | public class MainActivity extends AppCompatActivity implements ShopcartExpandableListViewAdapter.CheckInterface, View.OnClickListener, ShopcartExpandableListViewAdapter.ModifyCountInterface { 25 | private SuperExpandableListView exListView; 26 | private CheckBox cb_check_all; 27 | private TextView tv_total_price; 28 | private TextView tv_delete; 29 | private TextView tv_go_to_pay; 30 | private Context context; 31 | 32 | private double totalPrice = 0.00;// 购买的商品总价 33 | private int totalCount = 0;// 购买的商品总数量 34 | 35 | private ShopcartExpandableListViewAdapter selva; 36 | private List groups = new ArrayList();// 组元素数据列表 37 | private Map> children = new HashMap<>();// 子元素数据列表 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | // requestWindowFeature(Window.FEATURE_NO_TITLE); 43 | setContentView(R.layout.activity_main); 44 | 45 | initView(); 46 | initEvents(); 47 | } 48 | 49 | private void initView() { 50 | context = this; 51 | virtualData(); 52 | exListView = (SuperExpandableListView) findViewById(R.id.exListView); 53 | cb_check_all = (CheckBox) findViewById(R.id.all_chekbox); 54 | tv_total_price = (TextView) findViewById(R.id.tv_total_price); 55 | tv_delete = (TextView) findViewById(R.id.tv_delete); 56 | tv_go_to_pay = (TextView) findViewById(R.id.tv_go_to_pay); 57 | } 58 | 59 | private void initEvents() { 60 | selva = new ShopcartExpandableListViewAdapter(groups, children, this); 61 | selva.setCheckInterface(this);// 关键步骤1,设置复选框接口 62 | selva.setModifyCountInterface(this);// 关键步骤2,设置数量增减接口 63 | exListView.setAdapter(selva); 64 | 65 | for (int i = 0; i < selva.getGroupCount(); i++) { 66 | exListView.expandGroup(i);// 关键步骤3,初始化时,将ExpandableListView以展开的方式呈现 67 | } 68 | 69 | cb_check_all.setOnClickListener(this); 70 | tv_delete.setOnClickListener(this); 71 | tv_go_to_pay.setOnClickListener(this); 72 | } 73 | 74 | /** 75 | * 模拟数据
76 | * 遵循适配器的数据列表填充原则,组元素被放在一个List中,对应的组元素下辖的子元素被放在Map中,
77 | * 其键是组元素的Id(通常是一个唯一指定组元素身份的值) 78 | */ 79 | private void virtualData() { 80 | 81 | for (int i = 0; i < 7; i++) { 82 | groups.add(new GroupInfo(i + "", "第八号当铺" + (i + 1) + "号店")); 83 | List products = new ArrayList<>(); 84 | for (int j = 0; j <= i; j++) { 85 | products.add(new ProductInfo(j + "", "商品", "", groups.get(i).getName() + "的第" + (j + 1) + "个商品", 120.00 + i * j, 1+j)); 86 | } 87 | children.put(groups.get(i).getId(), products);// 将组元素的一个唯一值,这里取Id,作为子元素List的Key 88 | } 89 | } 90 | 91 | @Override 92 | public void checkGroup(int groupPosition, boolean isChecked) { 93 | GroupInfo group = groups.get(groupPosition); 94 | List childs = children.get(group.getId()); 95 | for (int i = 0; i < childs.size(); i++) { 96 | childs.get(i).setChoosed(isChecked); 97 | } 98 | if (isAllCheck()) 99 | cb_check_all.setChecked(true); 100 | else 101 | cb_check_all.setChecked(false); 102 | selva.notifyDataSetChanged(); 103 | calculate(); 104 | } 105 | 106 | @Override 107 | public void checkChild(int groupPosition, int childPosition, boolean isChecked) { 108 | boolean allChildSameState = true;// 判断改组下面的所有子元素是否是同一种状态 109 | GroupInfo group = groups.get(groupPosition); 110 | List childs = children.get(group.getId()); 111 | for (int i = 0; i < childs.size(); i++) { 112 | if (childs.get(i).isChoosed() != isChecked) { 113 | allChildSameState = false; 114 | break; 115 | } 116 | } 117 | if (allChildSameState) { 118 | group.setChoosed(isChecked);// 如果所有子元素状态相同,那么对应的组元素被设为这种统一状态 119 | } else { 120 | group.setChoosed(false);// 否则,组元素一律设置为未选中状态 121 | } 122 | 123 | if (isAllCheck()) 124 | cb_check_all.setChecked(true); 125 | else 126 | cb_check_all.setChecked(false); 127 | selva.notifyDataSetChanged(); 128 | calculate(); 129 | } 130 | 131 | @Override 132 | public void doIncrease(int groupPosition, int childPosition, View showCountView, boolean isChecked) { 133 | ProductInfo product = (ProductInfo) selva.getChild(groupPosition, childPosition); 134 | int currentCount = product.getCount(); 135 | currentCount++; 136 | product.setCount(currentCount); 137 | ((TextView) showCountView).setText(currentCount + ""); 138 | 139 | selva.notifyDataSetChanged(); 140 | calculate(); 141 | } 142 | 143 | @Override 144 | public void doDecrease(int groupPosition, int childPosition, View showCountView, boolean isChecked) { 145 | ProductInfo product = (ProductInfo) selva.getChild(groupPosition, childPosition); 146 | int currentCount = product.getCount(); 147 | if (currentCount == 1) 148 | return; 149 | currentCount--; 150 | 151 | product.setCount(currentCount); 152 | ((TextView) showCountView).setText(currentCount + ""); 153 | 154 | selva.notifyDataSetChanged(); 155 | calculate(); 156 | } 157 | 158 | @Override 159 | public void onClick(View v) { 160 | AlertDialog alert; 161 | switch (v.getId()) { 162 | case R.id.all_chekbox: 163 | doCheckAll(); 164 | break; 165 | case R.id.tv_go_to_pay: 166 | if (totalCount == 0) { 167 | Toast.makeText(context, "请选择要支付的商品", Toast.LENGTH_LONG).show(); 168 | return; 169 | } 170 | alert = new AlertDialog.Builder(context).create(); 171 | alert.setTitle("操作提示"); 172 | alert.setMessage("总计:\n" + totalCount + "种商品\n" + totalPrice + "元"); 173 | alert.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() { 174 | @Override 175 | public void onClick(DialogInterface dialog, int which) { 176 | return; 177 | } 178 | }); 179 | alert.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener(){ 180 | @Override 181 | public void onClick(DialogInterface dialog, int which) { 182 | return; 183 | } 184 | }); 185 | alert.show(); 186 | break; 187 | case R.id.tv_delete: 188 | if (totalCount == 0) { 189 | Toast.makeText(context, "请选择要移除的商品", Toast.LENGTH_LONG).show(); 190 | return; 191 | } 192 | alert = new AlertDialog.Builder(context).create(); 193 | alert.setTitle("操作提示"); 194 | alert.setMessage("您确定要将这些商品从购物车中移除吗?"); 195 | alert.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() { 196 | @Override 197 | public void onClick(DialogInterface dialog, int which) { 198 | return; 199 | } 200 | }); 201 | alert.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() { 202 | @Override 203 | public void onClick(DialogInterface dialog, int which) 204 | { 205 | doDelete(); 206 | } 207 | }); 208 | alert.show(); 209 | break; 210 | } 211 | } 212 | 213 | /** 214 | * 删除操作
215 | * 1.不要边遍历边删除,容易出现数组越界的情况
216 | * 2.现将要删除的对象放进相应的列表容器中,待遍历完后,以removeAll的方式进行删除 217 | */ 218 | public void doDelete() { 219 | List toBeDeleteGroups = new ArrayList();// 待删除的组元素列表 220 | for (int i = 0; i < groups.size(); i++) { 221 | GroupInfo group = groups.get(i); 222 | if (group.isChoosed()) { 223 | 224 | toBeDeleteGroups.add(group); 225 | } 226 | List toBeDeleteProducts = new ArrayList();// 待删除的子元素列表 227 | List childs = children.get(group.getId()); 228 | for (int j = 0; j < childs.size(); j++) { 229 | if (childs.get(j).isChoosed()) { 230 | toBeDeleteProducts.add(childs.get(j)); 231 | } 232 | } 233 | childs.removeAll(toBeDeleteProducts); 234 | 235 | } 236 | 237 | groups.removeAll(toBeDeleteGroups); 238 | 239 | selva.notifyDataSetChanged(); 240 | calculate(); 241 | } 242 | 243 | /** 全选与反选 */ 244 | private void doCheckAll() { 245 | for (int i = 0; i < groups.size(); i++) { 246 | groups.get(i).setChoosed(cb_check_all.isChecked()); 247 | GroupInfo group = groups.get(i); 248 | List childs = children.get(group.getId()); 249 | for (int j = 0; j < childs.size(); j++) { 250 | childs.get(j).setChoosed(cb_check_all.isChecked()); 251 | } 252 | } 253 | selva.notifyDataSetChanged(); 254 | calculate(); 255 | } 256 | 257 | /** 258 | * 统计操作
259 | * 1.先清空全局计数器
260 | * 2.遍历所有子元素,只要是被选中状态的,就进行相关的计算操作
261 | * 3.给底部的textView进行数据填充 262 | */ 263 | private void calculate() { 264 | totalCount = 0; 265 | totalPrice = 0.00; 266 | for (int i = 0; i < groups.size(); i++) { 267 | GroupInfo group = groups.get(i); 268 | List childs = children.get(group.getId()); 269 | for (int j = 0; j < childs.size(); j++) { 270 | ProductInfo product = childs.get(j); 271 | if (product.isChoosed()) { 272 | totalCount++; 273 | totalPrice += product.getPrice() * product.getCount(); 274 | } 275 | } 276 | } 277 | tv_total_price.setText("¥" + totalPrice); 278 | tv_go_to_pay.setText("去支付(" + totalCount + ")"); 279 | } 280 | 281 | private boolean isAllCheck() { 282 | for (GroupInfo group : groups) { 283 | if (!group.isChoosed()) 284 | return false; 285 | } 286 | return true; 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ShoppingCart 2 | 一个仿京东、淘宝等购物车的效果,并支持侧滑删除效果 3 | 4 | 1、使用一个继承ExpandableListView的SuperExpandableListView类来实现购物车的分组的效果 5 | ### SuperExpandableListView.java 6 | ```java 7 | public class SuperExpandableListView extends ExpandableListView { 8 | 9 | private static final String TAG = SuperExpandableListView.class.getCanonicalName(); 10 | /** 11 | * 用户滑动最小距离 12 | */ 13 | private int touchSlop; 14 | /** 15 | * 是否相应滑动 16 | */ 17 | private boolean isSliding; 18 | /** 19 | * 手指按下时x坐标 20 | */ 21 | private int xDown; 22 | /** 23 | * 手指按下时的y坐标 24 | */ 25 | private int yDown; 26 | /** 27 | * 手指移动时的x坐标 28 | */ 29 | private int xMove; 30 | /** 31 | * 手指移动时的y坐标 32 | */ 33 | private int yMove; 34 | 35 | boolean isChild; 36 | 37 | private LayoutInflater mInflater; 38 | 39 | private ViewGroup itemLayout; 40 | 41 | private SlideView mFocusedItemView; 42 | 43 | /** 44 | * 为删除按钮提供一个回调接口 45 | */ 46 | private ButtonClickListener mListener; 47 | /** 48 | * 当前手指触摸的View 49 | */ 50 | 51 | /** 52 | * 当前手指触摸的位置 53 | */ 54 | private int mCurrentViewPos = -1; 55 | 56 | public SuperExpandableListView(Context context, AttributeSet attrs, 57 | int defStyle) { 58 | super(context, attrs, defStyle); 59 | initData(context); 60 | // TODO Auto-generated constructor stub 61 | } 62 | 63 | public SuperExpandableListView(Context context, AttributeSet attrs) { 64 | super(context, attrs); 65 | // TODO Auto-generated constructor stub 66 | initData(context); 67 | } 68 | 69 | public SuperExpandableListView(Context context) { 70 | super(context); 71 | // TODO Auto-generated constructor stub 72 | initData(context); 73 | } 74 | 75 | private void initData(Context context) { 76 | mInflater = LayoutInflater.from(context); 77 | touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 78 | } 79 | 80 | @Override 81 | public boolean dispatchTouchEvent(MotionEvent ev) { 82 | int action = ev.getAction(); 83 | int x = (int) ev.getX(); 84 | int y = (int) ev.getY(); 85 | switch (action) { 86 | case MotionEvent.ACTION_DOWN: 87 | // isSliding = false; 88 | // if(isSliding){ 89 | // a 90 | // } 91 | xDown = x; 92 | yDown = y; 93 | // 获得当前手指按下时的item的位置 94 | int position = pointToPosition(xDown, yDown); 95 | if (mCurrentViewPos != position || isSliding) { 96 | mCurrentViewPos = position; 97 | isSliding = false; 98 | if (mFocusedItemView != null) { 99 | mFocusedItemView.reset(); 100 | } 101 | } 102 | // 获得当前手指按下时的item 103 | itemLayout = (ViewGroup) getChildAt(mCurrentViewPos - getFirstVisiblePosition()); 104 | if (itemLayout != null) { 105 | int id = itemLayout.getId(); 106 | if (id == R.id.SwipeMenuExpandableListView) { 107 | isChild = false; 108 | } else { 109 | isChild = true; 110 | } 111 | /*if(itemLayout instanceof RelativeLayout){ 112 | isChild = false; 113 | }else{ 114 | isChild = true; 115 | }*/ 116 | } 117 | break; 118 | case MotionEvent.ACTION_MOVE: 119 | xMove = x; 120 | yMove = y; 121 | int dx = xMove - xDown; 122 | int dy = yMove - yDown; 123 | /** 124 | * 判断是否是从右到左的滑动 125 | */ 126 | if (xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop && isChild) { 127 | // Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx + " , dy = " + dy); 128 | isSliding = true; 129 | } 130 | break; 131 | } 132 | return super.dispatchTouchEvent(ev); 133 | } 134 | 135 | @Override 136 | public boolean onTouchEvent(MotionEvent ev) { 137 | int action = ev.getAction(); 138 | int x = (int) ev.getX(); 139 | int y = (int) ev.getY(); 140 | /** 141 | * 如果是从右到左的滑动才相应 142 | */ 143 | if (isSliding) { 144 | switch (action) { 145 | case MotionEvent.ACTION_MOVE: 146 | if (mCurrentViewPos != -1) { 147 | if (Math.abs(yDown - y) < 30 && Math.abs(xDown - x) > 20) { 148 | int first = this.getFirstVisiblePosition(); 149 | int index = mCurrentViewPos - first; 150 | mFocusedItemView = (SlideView) getChildAt(index); 151 | mFocusedItemView.onTouchEvent(ev); 152 | return true; 153 | } 154 | } 155 | 156 | break; 157 | case MotionEvent.ACTION_UP: 158 | isChild = false; 159 | if (isSliding) { 160 | // isSliding = false; 161 | if (mFocusedItemView != null) { 162 | mFocusedItemView.adjust(xDown - x > 0); 163 | return true; 164 | } 165 | } 166 | } 167 | // 相应滑动期间屏幕itemClick事件,避免发生冲突 168 | return true; 169 | } 170 | 171 | return super.onTouchEvent(ev); 172 | } 173 | 174 | public void setButtonClickListener(ButtonClickListener listener) { 175 | mListener = listener; 176 | } 177 | 178 | interface ButtonClickListener { 179 | public void clickHappend(int position); 180 | } 181 | } 182 | ``` 183 | 2、使用一个继承LinearLayout的SlideView来实现左滑删除效果 184 | ### SlideView.java 185 | ```java 186 | public class SlideView extends LinearLayout { 187 | public static final String TAG = "SlideView"; 188 | 189 | private static final int TAN = 2; 190 | private int mHolderWidth = 90; 191 | private float mLastX = 0; 192 | private float mLastY = 0; 193 | private LinearLayout mViewContent; 194 | private Scroller mScroller; 195 | private Context mContext; 196 | private Resources mResources; 197 | 198 | public TextView getBack() { 199 | return back; 200 | } 201 | 202 | private TextView back; 203 | 204 | public SlideView(Context context, Resources resources, View content) { 205 | super(context); 206 | initView(context, resources, content); 207 | } 208 | 209 | 210 | public SlideView(Context context, AttributeSet attrs) { 211 | super(context, attrs); 212 | // TODO Auto-generated constructor stub 213 | initView(context, context.getResources(), null); 214 | } 215 | 216 | public SlideView(Context context) { 217 | super(context); 218 | // TODO Auto-generated constructor stub 219 | initView(context, context.getResources(), null); 220 | } 221 | private void initView(Context context, Resources resources, View content) { 222 | // TODO Auto-generated method stub 223 | setOrientation(LinearLayout.HORIZONTAL); 224 | this.mContext = context; 225 | this.mResources = resources; 226 | Log.i(TAG, "---1---"); 227 | mScroller = new Scroller(context); 228 | Log.i(TAG, "---2---"); 229 | View view = LayoutInflater.from(context).inflate(resources.getLayout(R.layout.slide_view_merge), this); 230 | Log.i(TAG, "---3---"); 231 | // view.findViewById(R.id.holder).setBackground(resources.getDrawable(R.drawable.selector_slider_holder)); 232 | Log.i(TAG, "---4---"); 233 | // shenhe = (TextView) view.findViewById(R.id.shenhe); 234 | // back = (TextView) findViewById(R.id.back); 235 | // back.setCompoundDrawablesWithIntrinsicBounds(null, resources.getDrawable(R.drawable.back), null, null); 236 | // back.setOnClickListener(this); 237 | // shenhe.setOnClickListener(this); 238 | mViewContent = (LinearLayout) view.findViewById(R.id.view_content); 239 | // mHolderWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources().getDisplayMetrics())); 240 | mHolderWidth = getResources().getDimensionPixelSize(R.dimen.width_); 241 | if(content!=null){ 242 | mViewContent.addView(content); 243 | } 244 | } 245 | 246 | @Override 247 | public boolean onTouchEvent(MotionEvent event) { 248 | switch (event.getAction()) { 249 | case MotionEvent.ACTION_MOVE: 250 | float x = event.getX(); 251 | float y = event.getY(); 252 | float deltaX = x - mLastX; 253 | float deltaY = y - mLastY; 254 | mLastX = x; 255 | mLastY = y; 256 | if(Math.abs(deltaX) mHolderWidth){ 264 | newScrollX = mHolderWidth; 265 | } 266 | this.scrollTo((int)newScrollX, 0); 267 | } 268 | break; 269 | } 270 | return super.onTouchEvent(event); 271 | } 272 | 273 | private void smoothScrollTo(int destX, int destY) { 274 | int scrollX = getScrollX(); 275 | int delta = destX - scrollX; 276 | mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3); 277 | invalidate(); 278 | } 279 | 280 | @Override 281 | public void computeScroll() { 282 | if (mScroller.computeScrollOffset()) { 283 | scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); 284 | postInvalidate(); 285 | } 286 | } 287 | /** 288 | * 获取view是需要重置缓存状态 289 | */ 290 | public void shrink() { 291 | int offset = getScrollX(); 292 | if (offset == 0) { 293 | return; 294 | } 295 | scrollTo(0, 0); 296 | } 297 | 298 | public void setContentView(View view) { 299 | if (mViewContent != null) { 300 | mViewContent.addView(view); 301 | } 302 | } 303 | 304 | public void reset() { 305 | int offset = getScrollX(); 306 | if (offset == 0) { 307 | return; 308 | } 309 | smoothScrollTo(0, 0); 310 | } 311 | 312 | public void adjust(boolean left) { 313 | int offset = getScrollX(); 314 | if (offset == 0) { 315 | return; 316 | } 317 | if (offset < 20) { 318 | this.smoothScrollTo(0, 0); 319 | } else if (offset < mHolderWidth - 20) { 320 | if (left) { 321 | this.smoothScrollTo(mHolderWidth, 0); 322 | } else { 323 | this.smoothScrollTo(0, 0); 324 | } 325 | } else { 326 | this.smoothScrollTo(mHolderWidth, 0); 327 | } 328 | } 329 | } 330 | ``` 331 | 我的代码还有些需要完善的,还请多多指教! 332 | 如果你觉得我的代码对你有帮助,请麻烦你在右上角给我一个star.^_^ 333 | 334 | #效果图 335 | ![image](https://github.com/itzuo/ShoppingCart/blob/master/GIF.gif) 336 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | 8 | #999999 9 | 10 | #D7D7D7 11 | #ffffff 12 | 13 | #fffff0 14 | 15 | #ffffe0 16 | #3060a4e3 17 | 18 | 19 | #ffff00 20 | 21 | #fffafa 22 | 23 | #fffaf0 24 | 25 | #fffacd 26 | 27 | #fff8dc 28 | 29 | #fff5ee 30 | 31 | #fff0f5 32 | 33 | #ffefd5 34 | 35 | #ffebcd 36 | 37 | #ffe4e1 38 | 39 | #ffe4c4 40 | 41 | #ffe4b5 42 | 43 | #ffdead 44 | 45 | #ffdab9 46 | 47 | #ffd700 48 | 49 | #ffc0cb 50 | 51 | #ffb6c1 52 | 53 | #fd7903 54 | 55 | #ffa07a 56 | 57 | #ff8c00 58 | 59 | #ff7f50 60 | 61 | #ff69b4 62 | 63 | #ff6347 64 | 65 | #ff4500 66 | 67 | #ff1493 68 | 69 | #ff00ff 70 | 71 | #ff00ff 72 | 73 | #ff0000 74 | 75 | #fdf5e6 76 | 77 | #fafad2 78 | 79 | #faf0e6 80 | 81 | #faebd7 82 | 83 | #fa8072 84 | 85 | #f8f8ff 86 | 87 | #f5fffa 88 | 89 | #f5f5f5 90 | 91 | #f5f5dc 92 | 93 | #f5deb3 94 | 95 | #f4a460 96 | 97 | #f0ffff 98 | 99 | #f0fff0 100 | 101 | #f0f8ff 102 | 103 | #f0e68c 104 | 105 | #f08080 106 | 107 | #eee8aa 108 | 109 | #ee82ee 110 | 111 | #e9967a 112 | 113 | #e6e6fa 114 | 115 | #e0ffff 116 | 117 | #deb887 118 | 119 | #dda0dd 120 | 121 | #dcdcdc 122 | 123 | #dc143c 124 | 125 | #db7093 126 | 127 | #daa520 128 | 129 | #da70d6 130 | 131 | #d8bfd8 132 | 133 | #d3d3d3 134 | 135 | #d3d3d3 136 | 137 | #d2b48c 138 | 139 | #d2691e 140 | 141 | #cd853f 142 | 143 | #cd5c5c 144 | 145 | #c71585 146 | 147 | #c0c0c0 148 | 149 | #bdb76b 150 | 151 | #bc8f8f 152 | 153 | #ba55d3 154 | 155 | #b8860b 156 | 157 | #b22222 158 | 159 | #b0e0e6 160 | 161 | #b0c4de 162 | 163 | #afeeee 164 | 165 | #adff2f 166 | 167 | #add8e6 168 | 169 | #a9a9a9 170 | 171 | #a9a9a9 172 | 173 | #a52a2a 174 | 175 | #a0522d 176 | 177 | #9932cc 178 | 179 | #98fb98 180 | 181 | #9400d3 182 | 183 | #9370db 184 | 185 | #90ee90 186 | 187 | #8fbc8f 188 | 189 | #8b4513 190 | 191 | #8b008b 192 | 193 | #8b0000 194 | 195 | #8a2be2 196 | 197 | #87cefa 198 | 199 | #87ceeb 200 | 201 | #808080 202 | 203 | #7c7b7b 204 | 205 | #808000 206 | 207 | #800080 208 | 209 | #800000 210 | 211 | #7fffd4 212 | 213 | #7fff00 214 | 215 | #7cfc00 216 | 217 | #7b68ee 218 | 219 | #778899 220 | 221 | #778899 222 | 223 | #708090 224 | 225 | #708090 226 | 227 | #6b8e23 228 | 229 | #6a5acd 230 | 231 | #696969 232 | 233 | #696969 234 | 235 | #66cdaa 236 | 237 | #6495ed 238 | 239 | #5f9ea0 240 | 241 | #556b2f 242 | 243 | #4b0082 244 | 245 | #48d1cc 246 | 247 | #483d8b 248 | 249 | #4682b4 250 | 251 | #4169e1 252 | 253 | #40e0d0 254 | 255 | #3cb371 256 | 257 | #32cd32 258 | 259 | #2f4f4f 260 | 261 | #2f4f4f 262 | 263 | #2e8b57 264 | 265 | #228b22 266 | 267 | #20b2aa 268 | 269 | #1e90ff 270 | 271 | #191970 272 | 273 | #00ffff 274 | 275 | #00ffff 276 | 277 | #00ff7f 278 | 279 | #00ff00 280 | 281 | #00fa9a 282 | 283 | #00ced1 284 | 285 | #00bfff 286 | 287 | #008b8b 288 | 289 | #008080 290 | 291 | #008000 292 | 293 | #006400 294 | 295 | #005dc1 296 | 297 | #0000cd 298 | 299 | #00008b 300 | 301 | #000080 302 | 303 | #3B3B3B 304 | 305 | 306 | 307 | #0174E1 308 | #cbcbcb 309 | #eaeaea 310 | #fcfcfc 311 | #1e1d1d 312 | #eaeaea 313 | 314 | #464646 315 | 316 | #3c3c3c 317 | 318 | #3c3c3c 319 | #da1609 320 | #0f90e3 321 | #66c058 322 | #DAE532 323 | #0074E1 324 | 325 | #949494 326 | 327 | #c4c4c4 328 | 329 | 330 | #f2f2f2 331 | #fff 332 | 333 | 334 | #484848 335 | #7d7d7d 336 | 337 | 338 | #D21A3E 339 | #B41131 340 | #515151 341 | #646464 342 | #a1a1a1 343 | #b5b5b5 344 | #c4c4c4 345 | #b18500 346 | #f7f7f7 347 | #00FF99 348 | 349 | 350 | #f6f6f6 351 | #929292 352 | 353 | #464646 354 | #464646 355 | 356 | #ed3b3b 357 | #b0b0b0 358 | #232323 359 | 360 | #333333 361 | #777777 362 | #b0000000 363 | #60000000 364 | #c0ffff00 365 | #00000000 366 | #ffffff 367 | #fafafa 368 | #eeeeee 369 | #0067db 370 | 371 | #CDCEC9 372 | #C3C3C3 373 | #2e000000 374 | #f2f2f2 375 | 376 | #333333 377 | #666666 378 | #999999 379 | 380 | #de6838 381 | 382 | #E84A40 383 | #E22F2F 384 | 385 | --------------------------------------------------------------------------------