? = null
31 |
32 | private fun doLogic() {
33 | val goodImgUrl = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1282625489,100434574&fm=27&gp=0.jpg"
34 | Glide.with(this).load(goodImgUrl).placeholder(R.drawable.ic_launcher).into(iv_main)
35 |
36 | SpecSelectFragment.showDialog(this, null, defaultAttrList, spec, "该规格已无库存!")
37 | .setShowGoodImgListener { iv, imgUrl ->
38 | Log.e(TAG, "商品图片地址= $imgUrl iv对象--$iv")
39 | Glide.with(this).load(imgUrl).placeholder(R.drawable.ic_launcher).centerCrop().into(iv)
40 |
41 | }
42 | .setSubmitSpecCombListener { combBean, num, statusRestoreList ->
43 | defaultAttrList = statusRestoreList
44 | Log.e(TAG, " 描述---${combBean.desc} 数量---$num")
45 | tv.text = " 描述---${combBean.desc}---数量---$num"
46 | }
47 | }
48 |
49 | val spec: SpecBean by lazy { Gson().fromJson(json, SpecBean::class.java) }
50 |
51 | val json = """
52 | {
53 | "attrs": [
54 | {
55 | "key": "颜色",
56 | "value": [
57 | {
58 | "id": 3,
59 | "name": "红色",
60 | "ownId": 1
61 | },
62 | {
63 | "id": 4,
64 | "name": "蓝色",
65 | "ownId": 1
66 | }
67 | ]
68 | },
69 | {
70 | "key": "重量",
71 | "value": [
72 | {
73 | "id": 5,
74 | "name": "10KG",
75 | "ownId": 2
76 | },
77 | {
78 | "id": 6,
79 | "name": "20KG",
80 | "ownId": 2
81 | },
82 | {
83 | "id": 7,
84 | "name": "30KG",
85 | "ownId": 2
86 | }
87 | ]
88 | },
89 | {
90 | "key": "产地",
91 | "value": [
92 | {
93 | "id": 24,
94 | "name": "江油",
95 | "ownId": 22
96 | },
97 | {
98 | "id": 23,
99 | "name": "绵阳",
100 | "ownId": 22
101 | },
102 | {
103 | "id": 31,
104 | "name": "四川绵阳市涪城区的撒啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊",
105 | "ownId": 22
106 | }
107 | ]
108 | },
109 | {
110 | "key": "尺寸",
111 | "value": [
112 | {
113 | "id": 20,
114 | "name": "30cm",
115 | "ownId": 14
116 | },
117 | {
118 | "id": 19,
119 | "name": "20cm",
120 | "ownId": 14
121 | },
122 | {
123 | "id": 18,
124 | "name": "10cm",
125 | "ownId": 14
126 | }
127 | ]
128 | }
129 | ],
130 | "combs": [
131 | {
132 | "comb": "4,6,23,20",
133 | "desc": "蓝色-20KG-绵阳-30cm",
134 | "id": 10,
135 | "price": "1.0(可抵扣)",
136 | "productId": 5,
137 | "stock": 2,
138 | "specImg":"http://ww3.sinaimg.cn/mw600/0073ob6Pgy1fo91049t9mj30lc0w0dnh.jpg"
139 | },
140 | {
141 | "comb": "4,5,23,19",
142 | "desc": "蓝色-10KG-绵阳-20cm",
143 | "id": 8,
144 | "price": "22.0(可抵扣)",
145 | "productId": 5,
146 | "stock": 333,
147 | "specImg":"http://wx4.sinaimg.cn/mw600/0072bW0Xly1fo908gkyqjj30en0miabp.jpg"
148 | },
149 | {
150 | "comb": "4,5,24,19",
151 | "desc": "蓝色-10KG-江油-20cm",
152 | "id": 9,
153 | "price": "1.0(可抵扣)",
154 | "productId": 5,
155 | "stock": 2,
156 | "specImg":"http://wx1.sinaimg.cn/mw600/0072bW0Xly1fo8zz4znwyj30hq0qoabz.jpg"
157 | },
158 | {
159 | "comb": "3,6,24,18",
160 | "desc": "红色-20KG-江油-10",
161 | "id": 11,
162 | "price": "1.0(可抵扣)",
163 | "productId": 5,
164 | "stock": 2,
165 | "specImg":"http://wx2.sinaimg.cn/mw600/0072bW0Xly1fo8zf0pn15j30ia0tzdox.jpg"
166 | }
167 | ]
168 | }
169 | """.trimIndent()
170 | }
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/aty_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
20 |
21 |
29 |
30 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #3F51B5
5 | #303F9F
6 | #FF4081
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | demo
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/io/github/wongxd/demo/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.demo
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/art/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/art/demo.gif
--------------------------------------------------------------------------------
/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.3.11'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.2.1'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | maven { url "https://jitpack.io" }
23 | }
24 | }
25 |
26 | task clean(type: Delete) {
27 | delete rootProject.buildDir
28 | }
29 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jan 11 09:34:56 CST 2019
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.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':skulibray'
2 |
--------------------------------------------------------------------------------
/skulibray/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/skulibray/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | // 你的GitHub账户名
4 | group = 'com.github.wongxd'
5 |
6 | android {
7 | compileSdkVersion 26
8 |
9 |
10 |
11 | defaultConfig {
12 | minSdkVersion 15
13 | targetSdkVersion 26
14 | versionCode 1
15 | versionName "0.0.5"
16 |
17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
18 |
19 | }
20 |
21 | buildTypes {
22 | release {
23 | minifyEnabled false
24 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
25 | }
26 | }
27 |
28 | }
29 |
30 | dependencies {
31 | implementation fileTree(dir: 'libs', include: ['*.jar'])
32 | testImplementation 'junit:junit:4.12'
33 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
34 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
35 | implementation 'com.android.support:appcompat-v7:26.1.0'
36 | implementation 'com.android.support:recyclerview-v7:26.1.0'
37 | }
38 |
--------------------------------------------------------------------------------
/skulibray/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/skulibray/src/androidTest/java/io/github/wongxd/skulibray/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("io.github.wongxd.skulibray.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/skulibray/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/SpecSelectFragment.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect;
2 |
3 | import android.app.Dialog;
4 | import android.app.DialogFragment;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v7.app.AlertDialog;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.text.TextUtils;
13 | import android.util.Log;
14 | import android.view.Gravity;
15 | import android.view.View;
16 | import android.view.Window;
17 | import android.view.WindowManager;
18 | import android.widget.ImageView;
19 | import android.widget.LinearLayout;
20 | import android.widget.TextView;
21 |
22 | import java.util.ArrayList;
23 | import java.util.HashMap;
24 | import java.util.List;
25 | import java.util.Map;
26 |
27 | import io.github.wongxd.skulibray.R;
28 | import io.github.wongxd.skulibray.specSelect.bean.SpecBean;
29 | import io.github.wongxd.skulibray.specSelect.custom.DensityUtil;
30 | import io.github.wongxd.skulibray.specSelect.custom.SkuLooper;
31 | import io.github.wongxd.skulibray.specSelect.custom.SpaceItemDecoration;
32 | import io.github.wongxd.skulibray.specSelect.custom.SpecLayoutManager;
33 | import io.github.wongxd.skulibray.specSelect.custom.TU;
34 | import io.github.wongxd.skulibray.specSelect.listener.ShowGoodImgListener;
35 | import io.github.wongxd.skulibray.specSelect.listener.SubmitSpecCombListener;
36 | import io.github.wongxd.skulibray.specSelect.observer.IObservable;
37 | import io.github.wongxd.skulibray.specSelect.observer.IObserver;
38 | import io.github.wongxd.skulibray.specSelect.observer.ObserverEventCode;
39 | import io.github.wongxd.skulibray.specSelect.observer.ObserverHolder;
40 | import io.github.wongxd.skulibray.specSelect.sku.ItemClickListener;
41 | import io.github.wongxd.skulibray.specSelect.sku.ProductModel;
42 | import io.github.wongxd.skulibray.specSelect.sku.SkuAdapter;
43 | import io.github.wongxd.skulibray.specSelect.sku.UiData;
44 | import io.github.wongxd.skulibray.specSelect.sku.skuLib.Sku;
45 | import io.github.wongxd.skulibray.specSelect.sku.skuLib.model.BaseSkuModel;
46 |
47 |
48 | /**
49 | * wongxd
50 | *
51 | * 参考 http://blog.csdn.net/wbwjx/article/details/50507344
52 | */
53 | public class SpecSelectFragment extends android.support.v4.app.DialogFragment implements IObserver {
54 | public static final String TAG = "SpecSelectFragment";
55 |
56 |
57 | private ImageView iv;
58 | private TextView tvPrice;
59 | private TextView tvStock;
60 | private TextView tvSpec;
61 | private TextView tvNum;
62 | private LinearLayout llSpecContainer;
63 |
64 | //展示商品图片
65 | private ShowGoodImgListener showGoodImgListener;
66 |
67 | //提交用户选择的规格
68 | private SubmitSpecCombListener submitSpecCombListener;
69 |
70 | private static SpecSelectFragment newInstance() {
71 | Bundle args = new Bundle();
72 | SpecSelectFragment fragment = new SpecSelectFragment();
73 | fragment.setArguments(args);
74 | return fragment;
75 | }
76 |
77 |
78 | @Override
79 | public void onCreate(Bundle savedInstanceState) {
80 | super.onCreate(savedInstanceState);
81 | // 必须在onCreate 中设置Style ,而在OnCreateView 中设置无效,因为此时对话框已经init了
82 | setStyle(DialogFragment.STYLE_NO_TITLE, R.style.BottomDialog);
83 | ObserverHolder.getInstance().register(this);
84 | }
85 |
86 | @Override
87 | public void onDestroyView() {
88 | ObserverHolder.getInstance().unregister(this);
89 | showGoodImgListener = null;
90 | submitSpecCombListener = null;
91 | bean = null;
92 | noStockTip = null;
93 | goodImgPath = null;
94 | checkedComb = null;
95 | super.onDestroyView();
96 | }
97 |
98 | @NonNull
99 | @Override
100 | public Dialog onCreateDialog(Bundle savedInstanceState) {
101 |
102 | View view = initView();
103 |
104 |
105 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.BottomDialog);
106 |
107 | builder.setView(view);
108 |
109 | AlertDialog dialog = builder.create();
110 |
111 | dialog.setCanceledOnTouchOutside(true);
112 |
113 | // 设置宽度为屏宽、靠近屏幕底部。
114 | Window window = dialog.getWindow();
115 | WindowManager.LayoutParams wlp = window.getAttributes();
116 | wlp.gravity = Gravity.BOTTOM;
117 | //设置没有效果
118 | wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
119 | window.setAttributes(wlp);
120 |
121 |
122 | new Thread(new Runnable() {
123 | @Override
124 | public void run() {
125 | initData(bean);
126 | }
127 | }).start();
128 |
129 | return dialog;
130 | }
131 |
132 | @NonNull
133 | private View initView() {
134 | View view = View.inflate(getActivity(), R.layout.fgt_spec_select, null);
135 |
136 | iv = (ImageView) view.findViewById(R.id.iv);
137 | ImageView ivClose = (ImageView) view.findViewById(R.id.iv_close);
138 |
139 | tvPrice = (TextView) view.findViewById(R.id.tv_price);
140 | tvStock = (TextView) view.findViewById(R.id.tv_stock);
141 | tvSpec = (TextView) view.findViewById(R.id.tv_spec);
142 |
143 | ImageView ivReduce = (ImageView) view.findViewById(R.id.iv_reduce);
144 | ImageView ivAdd = (ImageView) view.findViewById(R.id.iv_add);
145 | tvNum = (TextView) view.findViewById(R.id.tv_num_edit);
146 |
147 | TextView tvSure = (TextView) view.findViewById(R.id.tv_sure);
148 |
149 | llSpecContainer = (LinearLayout) view.findViewById(R.id.ll_spec_container);
150 |
151 |
152 | ivClose.setOnClickListener(new View.OnClickListener() {
153 | @Override
154 | public void onClick(View v) {
155 | getDialog().dismiss();
156 | }
157 | });
158 |
159 |
160 | ivAdd.setOnClickListener(new View.OnClickListener() {
161 | @Override
162 | public void onClick(View v) {
163 | doNumLogic(true);
164 | }
165 | });
166 |
167 | ivReduce.setOnClickListener(new View.OnClickListener() {
168 | @Override
169 | public void onClick(View v) {
170 | doNumLogic(false);
171 | }
172 | });
173 |
174 | tvSure.setOnClickListener(new View.OnClickListener() {
175 | @Override
176 | public void onClick(View v) {
177 | doSure();
178 | }
179 | });
180 |
181 |
182 | return view;
183 | }
184 |
185 |
186 | @Override
187 | public void onStart() {
188 | super.onStart();
189 | //全屏
190 | Dialog dialog = getDialog();
191 | if (null != dialog && dialog.getWindow() != null) {
192 | dialog.getWindow().setLayout(-1, -2);
193 | }
194 | }
195 |
196 | /**
197 | * 确认选择的规格
198 | */
199 | private void doSure() {
200 | if (specId.equals("null")) {
201 | TU.t(tvSpec.getText().toString());
202 | return;
203 | }
204 | Integer num = Integer.valueOf(tvNum.getText().toString().trim());
205 | if (productStock < num) {
206 | TU.t("库存不足");
207 | return;
208 | }
209 |
210 | SpecBean.CombsBean combsBean = getCombsBean();
211 | if (submitSpecCombListener != null && combsBean != null) {
212 | submitSpecCombListener.onSubmit(combsBean, num, mUiData.getSelectedEntities());
213 | }
214 |
215 | getDialog().dismiss();
216 |
217 | }
218 |
219 | @Nullable
220 | private SpecBean.CombsBean getCombsBean() {
221 | SpecBean.CombsBean combsBean = null;
222 | for (SpecBean.CombsBean c : bean.getCombs()) {
223 | if (specId.equals(c.getComb())) {
224 | combsBean = c;
225 | }
226 | }
227 | return combsBean;
228 | }
229 |
230 |
231 | /**
232 | * 数量的加减
233 | *
234 | * @param isAdd
235 | */
236 | private void doNumLogic(boolean isAdd) {
237 | String numS = tvNum.getText().toString().trim();
238 | if (TextUtils.isEmpty(numS)) {
239 | tvNum.setText("1");
240 | return;
241 | }
242 | long num = Long.valueOf(numS);
243 | if (isAdd) {
244 | num++;
245 | } else {
246 | if (num <= 1) num = 1;
247 | else
248 | num--;
249 | }
250 | tvNum.setText(num + "");
251 | }
252 |
253 | private UiData mUiData;
254 | private ProductModel products;
255 |
256 |
257 | private void doShowSpecTips(String s) {
258 | tvSpec.setText(s);
259 | }
260 |
261 | /**
262 | * 选择的规格id
263 | */
264 | private String specId = "null";
265 |
266 | private CharSequence price = "";
267 |
268 | private long productStock = 0;
269 |
270 |
271 | private void doShowSpecId(String s) {
272 | specId = s;
273 | if (s.equals("null")) {
274 | tvStock.setText("");
275 | tvPrice.setText("");
276 | return;
277 | }
278 | s = s.substring(0, s.length() - 1);
279 | specId = s;
280 | productStock = mUiData.getResult().get(s).getStock();
281 | price = mUiData.getResult().get(s).getPrice();
282 | tvPrice.setText("¥ " + price);
283 | tvStock.setText("库存: " + productStock);
284 | try {
285 | String specImgPath = getCombsBean().getSpecImg();
286 | if (showGoodImgListener != null && !TextUtils.isEmpty(specImgPath)) {
287 | showGoodImgListener.displayImg(iv, specImgPath);
288 | }
289 | } catch (Exception e) {
290 | e.printStackTrace();
291 | }
292 | // Log.d(TAG, "specid " + s + " price" + mUiData.getResult().get(s).getPrice() + " stock" + mUiData.getResult().get(s).getStock());
293 | }
294 |
295 | /**
296 | * 用户点击 做出了选择
297 | *
298 | * @param observable 消息发布者
299 | * @param msg 发布的消息内容
300 | * @param flag 消息的类型标记
301 | */
302 | @Override
303 | public void onMessageReceived(IObservable observable, Object msg, int flag) {
304 |
305 | String info = (String) msg;
306 | switch (flag) {
307 | case ObserverEventCode.SKU_GETSPECID:
308 | doShowSpecId(info);
309 | break;
310 |
311 | case ObserverEventCode.SKU_TIPS:
312 | doShowSpecTips(info);
313 | break;
314 |
315 | default:
316 | break;
317 | }
318 | }
319 |
320 |
321 | /**
322 | * 初始化展示的数据
323 | */
324 | private void initData(SpecBean bean) {
325 |
326 | List attrs = bean.getAttrs();
327 |
328 | List pAttr = new ArrayList<>();
329 | int groupId = 0;
330 | for (SpecBean.AttrsBean attr : attrs) {
331 | ProductModel.AttributesEntity group = new ProductModel.AttributesEntity();
332 | group.setName(attr.getKey());
333 | group.setId(groupId);
334 | for (SpecBean.AttrsBean.ValueBean item : attr.getValue()) {
335 | group.getAttributeMembers()
336 | .add(new ProductModel.AttributesEntity.AttributeMembersEntity(groupId, item.getId(), item.getName()));
337 | }
338 | pAttr.add(group);
339 | groupId++;
340 | }
341 |
342 | List comb = bean.getCombs();
343 | Map initData = new HashMap<>();
344 | for (SpecBean.CombsBean g : comb) {
345 | initData.put(g.getComb(),
346 | new BaseSkuModel(g.getPrice() + "", g.getStock()));
347 | }
348 |
349 | /**
350 | * 所有规格 的 组名
351 | */
352 | List groupNameList = new ArrayList();
353 | for (SpecBean.AttrsBean s : attrs) {
354 | groupNameList.add(s.getKey());
355 | }
356 |
357 | mUiData = new UiData();
358 | mUiData.setGroupNameList(groupNameList);
359 | products = new ProductModel();
360 |
361 | products.setProductStocks(initData);
362 | products.setAttributes(pAttr);
363 |
364 | // SKU 计算
365 | mUiData.setResult(Sku.skuCollection(products.getProductStocks()));
366 |
367 | for (String key : mUiData.getResult().keySet()) {
368 | Log.d("SKU Result", "key = " + key + " value = " + mUiData.getResult().get(key));
369 | }
370 |
371 |
372 | SkuLooper.runOnUiThread(new Runnable() {
373 | @Override
374 | public void run() {
375 |
376 |
377 | SpaceItemDecoration decoration = new SpaceItemDecoration(DensityUtil.dp2px(3f), DensityUtil.dp2px(6f));
378 | //添加list组
379 | for (int i = 0; i < products.getAttributes().size(); i++) {
380 | View viewList = View.inflate(getContext(), R.layout.bottom_sheet_group, null);
381 | TextView tvTitle = (TextView) viewList.findViewById(R.id.tv_title);
382 | RecyclerView recyclerViewBottom = (RecyclerView) viewList.findViewById(R.id.recycler_bottom);
383 | SkuAdapter skuAdapter = new SkuAdapter(products.getAttributes().get(i).getAttributeMembers(), products.getAttributes().get(i).getName());
384 | mUiData.getAdapters().add(skuAdapter);
385 |
386 | SpecLayoutManager layoutManager = new SpecLayoutManager();
387 | layoutManager.setAutoMeasureEnabled(true); //必须,防止recyclerview高度为wrap时测量item高度0
388 |
389 | recyclerViewBottom.addItemDecoration(decoration);
390 | recyclerViewBottom.setLayoutManager(layoutManager);
391 | recyclerViewBottom.setAdapter(skuAdapter);
392 |
393 | tvTitle.setText(products.getAttributes().get(i).getName());
394 | llSpecContainer.addView(viewList);
395 | }
396 |
397 | //设置点击监听器
398 | for (SkuAdapter adapter : mUiData.getAdapters()) {
399 | ItemClickListener listener = new ItemClickListener(mUiData, adapter, noStockTip);
400 | adapter.setOnClickListener(listener);
401 | }
402 | // 初始化按钮
403 | for (int i = 0; i < mUiData.getAdapters().size(); i++) {
404 | for (ProductModel.AttributesEntity.AttributeMembersEntity entity : mUiData.getAdapters().get(i).getAttributeMembersEntities()) {
405 | if (mUiData.getResult().get(entity.getAttributeMemberId() + "") == null
406 | || mUiData.getResult().get(entity.getAttributeMemberId() + "").getStock() <= 0) {
407 | entity.setStatus(ProductModel.AttributeMemberStatus.UNCHECKABLE);
408 | }
409 | }
410 | }
411 |
412 |
413 | if (showGoodImgListener != null && !TextUtils.isEmpty(goodImgPath)) {
414 | showGoodImgListener.displayImg(iv, goodImgPath);
415 | }
416 |
417 |
418 | // 按传入的规格展示
419 | if (checkedComb != null) {
420 | for (ProductModel.AttributesEntity.AttributeMembersEntity attrEntity : checkedComb) {
421 |
422 | for (int i = 0; i < mUiData.getAdapters().size(); i++) {
423 | final SkuAdapter curAdapter = mUiData.getAdapters().get(i);
424 | boolean isNeedBreak = false;
425 | for (final ProductModel.AttributesEntity.AttributeMembersEntity entity : curAdapter.getAttributeMembersEntities()) {
426 |
427 | if (attrEntity.getAttributeMemberId() == entity.getAttributeMemberId()
428 | && attrEntity.getName().equals(entity.getName())) {
429 |
430 | Log.d("wongxd", "恢复状态 name " + attrEntity.getName() + " id " + attrEntity.getAttributeMemberId());
431 |
432 | curAdapter.getOnClickListener().onItemClickListener(entity);
433 |
434 | isNeedBreak = true;
435 | break;
436 | }
437 | }
438 |
439 | if (isNeedBreak) break;
440 | }
441 |
442 | }
443 |
444 | }
445 |
446 |
447 | }
448 | });
449 |
450 |
451 | }
452 |
453 |
454 | private static String noStockTip;
455 | private static String goodImgPath;
456 | private static List checkedComb = null;
457 | private static SpecBean bean = null;
458 |
459 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
460 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
461 | ////////////////////////////////////////////////////////外部调用方法///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
462 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
463 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
464 |
465 | /**
466 | * 确认按钮的颜色、规格选中后的颜色 可在 color 中定义 #3F51B5,即可实现颜色自定义
467 | *
468 | *
469 | * 可以避免重复
470 | *
471 | * @param aty
472 | * @param allSpecBean 规格对象 {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean}
473 | * @return
474 | */
475 | public static SpecSelectFragment showDialog(AppCompatActivity aty, @NonNull SpecBean allSpecBean) {
476 | return showDialog(aty, null, null, allSpecBean);
477 | }
478 |
479 | /**
480 | * 确认按钮的颜色、规格选中后的颜色 可在 color 中定义 #3F51B5,即可实现颜色自定义
481 | *
482 | *
483 | * 可以避免重复
484 | *
485 | * @param aty
486 | * @param defaultGoodImg 商品默认展示的图片,如果不需要选中,传入 null
487 | * @param allSpecBean 规格对象 {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean}
488 | * @return
489 | */
490 | public static SpecSelectFragment showDialog(AppCompatActivity aty, @Nullable String defaultGoodImg, @NonNull SpecBean allSpecBean) {
491 | return showDialog(aty, defaultGoodImg, null, allSpecBean);
492 | }
493 |
494 |
495 | /**
496 | * 确认按钮的颜色、规格选中后的颜色 可在 color 中定义 #3F51B5,即可实现颜色自定义
497 | *
498 | *
499 | * 可以避免重复
500 | *
501 | * @param aty
502 | * @param defaultGoodImg 商品默认展示的图片,如果不需要选中,传入 null
503 | * @param statusRestoreList 商品默认选中规格,如果不需要选中,传入 null
504 | * @param allSpecBean 规格对象 {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean}
505 | * @return
506 | */
507 | public static SpecSelectFragment showDialog(AppCompatActivity aty, @Nullable String defaultGoodImg,
508 | List statusRestoreList, @NonNull SpecBean allSpecBean) {
509 | return showDialog(aty, defaultGoodImg, statusRestoreList, allSpecBean, null);
510 | }
511 |
512 | /**
513 | * 确认按钮的颜色、规格选中后的颜色 可在 color 中定义 #3F51B5,即可实现颜色自定义
514 | *
515 | *
516 | * 可以避免重复
517 | *
518 | * @param aty
519 | * @param defaultGoodImg 商品默认展示的图片,如果不需要选中,传入 null
520 | * @param statusRestoreList 商品默认选中规格,如果不需要选中,传入 null
521 | * @param allSpecBean 规格对象 {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean}
522 | * @param defaultNoStockTip 点击了无库存的规格时,提示信息。如果不需要显示,传入 null
523 | * @return
524 | */
525 | public static SpecSelectFragment showDialog(AppCompatActivity aty, @Nullable String defaultGoodImg,
526 | List statusRestoreList, @NonNull SpecBean allSpecBean, @Nullable String defaultNoStockTip) {
527 |
528 | TU.register(aty.getApplicationContext());
529 | noStockTip = defaultNoStockTip;
530 | goodImgPath = defaultGoodImg;
531 | checkedComb = statusRestoreList;
532 | bean = allSpecBean;
533 | FragmentManager fragmentManager = aty.getSupportFragmentManager();
534 | SpecSelectFragment bottomDialogFragment =
535 | (SpecSelectFragment) fragmentManager.findFragmentByTag(TAG);
536 | if (null == bottomDialogFragment) {
537 | bottomDialogFragment = newInstance();
538 | }
539 |
540 | if (!aty.isFinishing()
541 | && null != bottomDialogFragment
542 | && !bottomDialogFragment.isAdded()) {
543 | fragmentManager.beginTransaction()
544 | .add(bottomDialogFragment, TAG)
545 | .commitAllowingStateLoss();
546 | }
547 |
548 | return bottomDialogFragment;
549 | }
550 |
551 | /**
552 | * 设置展示图片的listener
553 | *
554 | * @param showGoodImgListener
555 | */
556 | public SpecSelectFragment setShowGoodImgListener(ShowGoodImgListener showGoodImgListener) {
557 | this.showGoodImgListener = showGoodImgListener;
558 | return this;
559 | }
560 |
561 |
562 | /**
563 | * 设置 规格选择完成 后 提交 时的回掉
564 | *
565 | * @param submitSpecCombListener
566 | */
567 | public SpecSelectFragment setSubmitSpecCombListener(SubmitSpecCombListener submitSpecCombListener) {
568 | this.submitSpecCombListener = submitSpecCombListener;
569 | return this;
570 | }
571 |
572 |
573 | }
574 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/bean/SpecBean.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.bean;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by wongxd on 2018/1/29.
7 | *
8 | * 规格信息的pojo
9 | *
10 | * 你的 CombsBean 数据可以多余当前给出的,但不能没有这个类中定义的数据.
11 | *
12 | * 注意,ValueBean {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean.AttrsBean.ValueBean} 是不可以被拓展的。因为在
13 | * AttrsBean {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean.AttrsBean} 中 value 是个 List ,
14 | * 经过查看sun的说明文档,在java中是”不能创建一个确切的泛型类型的数组”的。
15 | * 所以,把 AttrsBean {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean.AttrsBean} 设置为 final。
16 | *
17 | * CombsBean {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean.CombsBean} 同理
18 | *
19 | * 可能你们后台返回的 AttrsBean.ValueBean 中,还会有 对应于 key 的 唯一的 id 值,以供属性分组使用,但是你可以选择不使用,因为,
20 | * 在代码中,我已经为每个属性组生成了 groupId。
21 | */
22 |
23 | public class SpecBean {
24 |
25 |
26 | // {"data" : {
27 | // "attrs":[
28 | // {"value":[{"id":3,"name":"红色"}], "key" : "颜色"}
29 | // ],
30 | //
31 | // "combs":[
32 | // {"id":10,"productId":5,"stock":2,"comb":"4,6,23,20","desc":"蓝色-20KG-绵阳-30cm","price":1.0,specImg:""}
33 | // ]
34 | //
35 | // }}
36 |
37 |
38 | private List attrs;
39 | private List combs;
40 |
41 | public List getAttrs() {
42 | return attrs;
43 | }
44 |
45 | public void setAttrs(List attrs) {
46 | this.attrs = attrs;
47 | }
48 |
49 | public List getCombs() {
50 | return combs;
51 | }
52 |
53 | public void setCombs(List combs) {
54 | this.combs = combs;
55 | }
56 |
57 | public static final class AttrsBean {
58 | /**
59 | * value : [{"id":3,"name":"红色"}]
60 | * key : 颜色
61 | */
62 |
63 | private String key;
64 | private List value;
65 |
66 | public String getKey() {
67 | return key;
68 | }
69 |
70 | public void setKey(String key) {
71 | this.key = key;
72 | }
73 |
74 | public List getValue() {
75 | return value;
76 | }
77 |
78 | public void setValue(List value) {
79 | this.value = value;
80 | }
81 |
82 | public static final class ValueBean {
83 | /**
84 | * id : 3 对应 combs->comb 中的数字
85 | * name : 红色
86 | */
87 |
88 | private int id;
89 | private String name;
90 |
91 | public int getId() {
92 | return id;
93 | }
94 |
95 | public void setId(int id) {
96 | this.id = id;
97 | }
98 |
99 | public String getName() {
100 | return name;
101 | }
102 |
103 | public void setName(String name) {
104 | this.name = name;
105 | }
106 | }
107 | }
108 |
109 | public static final class CombsBean {
110 | /**
111 | * id : 10
112 | * productId : 5
113 | * stock : 2
114 | * comb : 4,6,23,20
115 | * desc : 蓝色-20KG-绵阳-30cm
116 | * price : 1.0
117 | * specImg:""
118 | */
119 |
120 | private long id = 0L; // 有的 后台 使用 id 去判断选择的规格
121 | private long productId;
122 | private String productName;
123 | private int stock;
124 | private String comb; // 有的 后台 使用 组合 去判断选择的规格
125 | private String desc;
126 | private String specImg = ""; // 当前规格 对应的图片(非必需)
127 | private String price;
128 |
129 | public long getId() {
130 | return id;
131 | }
132 |
133 | public void setId(long id) {
134 | this.id = id;
135 | }
136 |
137 | public long getProductId() {
138 | return productId;
139 | }
140 |
141 | public void setProductId(long productId) {
142 | this.productId = productId;
143 | }
144 |
145 | public String getProductName() {
146 | return productName;
147 | }
148 |
149 | public void setProductName(String productName) {
150 | this.productName = productName;
151 | }
152 |
153 | public int getStock() {
154 | return stock;
155 | }
156 |
157 | public void setStock(int stock) {
158 | this.stock = stock;
159 | }
160 |
161 | public String getComb() {
162 | return comb;
163 | }
164 |
165 | public void setComb(String comb) {
166 | this.comb = comb;
167 | }
168 |
169 | public String getDesc() {
170 | return desc;
171 | }
172 |
173 | public void setDesc(String desc) {
174 | this.desc = desc;
175 | }
176 |
177 | public String getPrice() {
178 | return price;
179 | }
180 |
181 | public void setPrice(String price) {
182 | this.price = price;
183 | }
184 |
185 | public String getSpecImg() {
186 | return specImg;
187 | }
188 |
189 | public void setSpecImg(String specImg) {
190 | this.specImg = specImg;
191 | }
192 | }
193 |
194 |
195 | }
196 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/custom/DensityUtil.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.custom;
2 |
3 | import android.content.res.Resources;
4 |
5 | public class DensityUtil {
6 |
7 | float density;
8 |
9 | public DensityUtil() {
10 | density = Resources.getSystem().getDisplayMetrics().density;
11 | }
12 |
13 | /**
14 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
15 | */
16 | public static int dp2px(float dpValue) {
17 | return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);
18 | }
19 |
20 | /**
21 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
22 | */
23 | public static float px2dp(float pxValue) {
24 | return (pxValue / Resources.getSystem().getDisplayMetrics().density);
25 | }
26 |
27 | /**
28 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
29 | */
30 | public int dip2px(float dpValue) {
31 | return (int) (0.5f + dpValue * density);
32 | }
33 |
34 | /**
35 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
36 | */
37 | public float px2dip(float pxValue) {
38 | return (pxValue / density);
39 | }
40 | }
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/custom/SkuLooper.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.custom;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | public class SkuLooper extends Handler {
7 |
8 | static SkuLooper instance = new SkuLooper(Looper.getMainLooper());
9 |
10 | private SkuLooper(Looper looper) {
11 | super(looper);
12 | }
13 |
14 | public SkuLooper getInstance() {
15 | return instance;
16 | }
17 |
18 | public static void runOnUiThread(Runnable runnable) {
19 | if (Looper.getMainLooper().equals(Looper.myLooper())) {
20 | runnable.run();
21 | } else {
22 | instance.post(runnable);
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/custom/SpaceItemDecoration.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.custom;
2 |
3 | import android.graphics.Rect;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.View;
6 |
7 | public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
8 |
9 | private int c;
10 | private int r;
11 |
12 | /**
13 | *
14 | * @param row 竖直间距
15 | * @param clo 水平间距
16 | */
17 | public SpaceItemDecoration(int row,int clo) {
18 | this.r = row;
19 | this.c = clo;
20 | }
21 |
22 | @Override
23 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
24 | outRect.top = r;
25 | outRect.left = c;
26 | outRect.right = c;
27 | outRect.bottom = r;
28 | }
29 | }
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/custom/SpecLayoutManager.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.custom;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 |
6 | /**
7 | * 自动换行布局管理
8 | *
9 | *
10 | *layoutManager.setAutoMeasureEnabled(true); //必须,防止recyclerview高度为wrap时测量item高度0
11 | *
12 | */
13 | public class SpecLayoutManager extends RecyclerView.LayoutManager {
14 |
15 | @Override
16 | public RecyclerView.LayoutParams generateDefaultLayoutParams() {
17 | return new RecyclerView.LayoutParams(
18 | RecyclerView.LayoutParams.WRAP_CONTENT,
19 | RecyclerView.LayoutParams.WRAP_CONTENT);
20 | }
21 |
22 | @Override
23 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
24 | detachAndScrapAttachedViews(recycler);
25 |
26 | int sumWidth = getWidth();
27 |
28 | int curLineWidth = 0, curLineTop = 0;
29 | int lastLineMaxHeight = 0;
30 | for (int i = 0; i < getItemCount(); i++) {
31 | View view = recycler.getViewForPosition(i);
32 |
33 | addView(view);
34 | measureChildWithMargins(view, 0, 0);
35 | int width = getDecoratedMeasuredWidth(view);
36 | int height = getDecoratedMeasuredHeight(view);
37 |
38 | curLineWidth += width;
39 | if (curLineWidth <= sumWidth) {//不需要换行
40 | layoutDecorated(view, curLineWidth - width, curLineTop, curLineWidth, curLineTop + height);
41 | //比较当前行多有item的最大高度
42 | lastLineMaxHeight = Math.max(lastLineMaxHeight, height);
43 | } else {//换行
44 | curLineWidth = width;
45 | if (lastLineMaxHeight == 0) {
46 | lastLineMaxHeight = height;
47 | }
48 | //记录当前行top
49 | curLineTop += lastLineMaxHeight;
50 |
51 | layoutDecorated(view, 0, curLineTop, width, curLineTop + height);
52 | lastLineMaxHeight = height;
53 | }
54 | }
55 |
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/custom/TU.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.custom;
2 |
3 | import android.content.Context;
4 | import android.widget.Toast;
5 |
6 |
7 | /**
8 | * Created by wongxd on 2018/2/8.
9 | */
10 |
11 |
12 | public class TU {
13 | private static volatile Toast toast;
14 | public static Context c;
15 |
16 |
17 | private TU() {
18 | /* cannot be instantiated */
19 | throw new UnsupportedOperationException("cannot be instantiated");
20 | }
21 |
22 |
23 | public static void register(Context ctx) {
24 | c = ctx;
25 | }
26 |
27 | public static void t(String msg) {
28 | if (msg.isEmpty()) return;
29 | if (toast == null) {
30 | synchronized (TU.class) {
31 | if (toast == null) {
32 | toast = Toast.makeText(c, msg, Toast.LENGTH_SHORT);
33 | toast.show();
34 | }
35 | }
36 | } else {
37 | toast.setText(msg);
38 | toast.show();
39 | }
40 | }
41 |
42 | public static void t(int msgRes) {
43 | t(c.getString(msgRes));
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/listener/ShowGoodImgListener.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.listener;
2 |
3 | import android.widget.ImageView;
4 |
5 | /**
6 | * Created by wongxd on 2018/2/8.
7 | *
8 | * 展示商品图片的listener
9 | */
10 |
11 | public interface ShowGoodImgListener {
12 |
13 | void displayImg(ImageView iv, String imgUrl);
14 | }
15 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/listener/SubmitSpecCombListener.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.listener;
2 |
3 | import java.util.List;
4 |
5 | import io.github.wongxd.skulibray.specSelect.bean.SpecBean;
6 | import io.github.wongxd.skulibray.specSelect.sku.ProductModel;
7 |
8 | /**
9 | * Created by wongxd on 2018/2/8.
10 | *
11 | * 点击规格选择界面的 确定 按钮,提交所选规格组合的监听
12 | */
13 |
14 | public interface SubmitSpecCombListener {
15 |
16 | /**
17 | * @param combBean 所选规格的信息 {@link io.github.wongxd.skulibray.specSelect.bean.SpecBean.CombsBean}
18 | * @param num 选择的数量
19 | * @param statusRestoreList 用来展示一个选中的组合,在 {@link io.github.wongxd.skulibray.specSelect.SpecSelectFragment} 的 showDialog() 中会用到
20 | */
21 | void onSubmit(SpecBean.CombsBean combBean, int num, List statusRestoreList);
22 | }
23 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/observer/EventObservable.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.observer;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 被观察者的具体化,该类负责给观察者发送消息
8 | * 参考 {@link java.util.Observable}
9 | */
10 | public class EventObservable implements IObservable{
11 |
12 | /**
13 | * 存放消息订阅者
14 | */
15 | List observers = new ArrayList();
16 |
17 | public EventObservable() {
18 | }
19 |
20 | /**
21 | * 向消息订阅队列添加订阅者
22 | */
23 | @Override
24 | public void addObserver(IObserver observer) {
25 | if (observer == null) {
26 | throw new NullPointerException("EventObservable == null");
27 | }
28 | synchronized (this) {
29 | if (!observers.contains(observer)) {
30 | observers.add(observer);
31 | }
32 | }
33 | }
34 |
35 | /**
36 | * 获得订阅者的数量
37 | */
38 | public int countObservers() {
39 | return observers.size();
40 | }
41 |
42 | /**
43 | * 删除指定订阅者
44 | */
45 | @Override
46 | public synchronized void deleteObserver(IObserver observer) {
47 | observers.remove(observer);
48 | }
49 |
50 | /**
51 | * 删除所有订阅者.
52 | */
53 | public synchronized void deleteObservers() {
54 | observers.clear();
55 | }
56 |
57 | /**
58 | * 通知消息订阅队列里的每一个订阅者
59 | */
60 | public void notifyObservers(int flag) {
61 | notifyObservers(null,flag);
62 | }
63 | /**
64 | * 通知消息订阅队列里的每一个订阅者
65 | * @param data 给订阅者传递的参数
66 | */
67 | @SuppressWarnings("unchecked")
68 | @Override
69 | public void notifyObservers(Object data, int flag) {
70 | int size = 0;
71 | IObserver[] arrays = null;
72 | synchronized (this) {
73 | size = observers.size();
74 | arrays = new IObserver[size];
75 | observers.toArray(arrays);
76 | }
77 | if (arrays != null) {
78 | for (IObserver observer : arrays) {
79 | observer.onMessageReceived(this, data,flag);
80 | }
81 | }
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/observer/IObservable.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.observer;
2 |
3 | /**
4 | * 被观察者
5 | */
6 |
7 | public interface IObservable {
8 |
9 | /**
10 | * 删除指定订阅者
11 | */
12 | void deleteObserver(IObserver observer);
13 |
14 | /**
15 | * 向消息订阅队列添加订阅者
16 | */
17 | void addObserver(IObserver observer);
18 |
19 | /**
20 | * 通知消息订阅队列里的每一个订阅者
21 | *
22 | * @param data 给订阅者传递的参数
23 | * @param flag 标示
24 | */
25 | void notifyObservers(Object data, int flag);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/observer/IObserver.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.observer;
2 |
3 | /**
4 | * 消息订阅者(观察者)
5 | */
6 | public interface IObserver {
7 |
8 | /**
9 | * 当消息发布者发布消息的时候调用该方法
10 | *
11 | * @param observable 消息发布者
12 | * @param msg 发布的消息内容
13 | * @param flag 消息的类型标记
14 | */
15 | void onMessageReceived(IObservable observable, Object msg, int flag);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/observer/ObserverEventCode.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.observer;
2 |
3 | /**
4 | * Created by wongxd on 2018/2/8.
5 | */
6 |
7 | public class ObserverEventCode {
8 |
9 | /**
10 | * 当前选择完了所有的规格,并产生了一个组合
11 | * 通过用户的选择产生了一个新的规格 组合
12 | */
13 | public static final int SKU_GETSPECID = 1;
14 |
15 |
16 | /**
17 | * 提示用户还有那些规格组 没有被选择
18 | */
19 | public static final int SKU_TIPS = 2;
20 | }
21 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/observer/ObserverHolder.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.observer;
2 |
3 | /**
4 | * 订阅模式管理类
5 | *
6 | * @see http://blog.csdn.net/chengliang0315/article/details/53381539
7 | */
8 | public class ObserverHolder {
9 |
10 | private static ObserverHolder instance;
11 |
12 | private EventObservable observable;
13 |
14 | private ObserverHolder() {
15 | observable = new EventObservable();
16 | }
17 |
18 | public static ObserverHolder getInstance() {
19 | if (instance == null) {
20 | synchronized (ObserverHolder.class) {
21 | if (instance == null) {
22 | instance = new ObserverHolder();
23 | }
24 | }
25 | }
26 | return instance;
27 | }
28 |
29 | /**
30 | * 将消息接收者注册进来
31 | * (如果将Activity作为订阅者在此注册的时候,切记在onDestroy()里面移除注册,否则可能导致内存泄露)
32 | *
33 | * @param observer
34 | */
35 | public void register(IObserver observer) {
36 | observable.addObserver(observer);
37 | }
38 |
39 | /**
40 | * 将消息接收者移除注册
41 | */
42 | public void unregister(IObserver observer) {
43 | observable.deleteObserver(observer);
44 | }
45 |
46 | /**
47 | * 给订阅者发生消息
48 | *
49 | * @param data
50 | */
51 | public void notifyObservers(String data, int flag) {
52 | observable.notifyObservers(data, flag);
53 | }
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/sku/ItemClickListener.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.sku;
2 |
3 |
4 | import android.support.annotation.Nullable;
5 | import android.text.TextUtils;
6 | import android.util.Log;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import io.github.wongxd.skulibray.specSelect.custom.TU;
12 | import io.github.wongxd.skulibray.specSelect.observer.ObserverEventCode;
13 | import io.github.wongxd.skulibray.specSelect.observer.ObserverHolder;
14 |
15 |
16 | /**
17 | * wongxd
18 | * 参考 http://blog.csdn.net/u012589795/article/details/53304287
19 | */
20 | public class ItemClickListener implements SkuAdapter.OnClickListener {
21 |
22 | private String TAG = getClass().getSimpleName();
23 |
24 | private UiData mUiData;
25 | private SkuAdapter mCurrentAdapter;
26 | private String mNoStockTip;
27 |
28 | public ItemClickListener(UiData uiData, SkuAdapter currentAdapter, @Nullable String noStockTip) {
29 | mUiData = uiData;
30 | mCurrentAdapter = currentAdapter;
31 | mNoStockTip = noStockTip;
32 | }
33 |
34 | @Override
35 | public void onItemClickListener(int position) {
36 | onItemClickListener(mCurrentAdapter.getAttributeMembersEntities().get(position));
37 | }
38 |
39 | @Override
40 | public void onItemClickListener(ProductModel.AttributesEntity.AttributeMembersEntity attributeMembersEntity) {
41 | //屏蔽不可点击
42 | if (attributeMembersEntity.getStatus() == ProductModel.AttributeMemberStatus.UNCHECKABLE) {
43 | if (null != mNoStockTip && !TextUtils.isEmpty(mNoStockTip)) {
44 | TU.t(mNoStockTip);
45 | }
46 | return;
47 | }
48 | // 设置当前单选点击
49 | for (ProductModel.AttributesEntity.AttributeMembersEntity entity : mCurrentAdapter.getAttributeMembersEntities()) {
50 | if (entity.equals(attributeMembersEntity)) {
51 | String key = mCurrentAdapter.groupName;
52 | if (mCurrentAdapter.getCurrentSelectedItem() == null || !mCurrentAdapter.getCurrentSelectedItem().equals(entity)) {
53 | entity.setStatus(ProductModel.AttributeMemberStatus.CHECKED);
54 | //添加已经选择的对象
55 | mCurrentAdapter.setCurrentSelectedItem(entity);
56 | mUiData.getSelectedMap().put(key, entity);
57 | } else {
58 | entity.setStatus(ProductModel.AttributeMemberStatus.CHECKABLE);
59 | mCurrentAdapter.setCurrentSelectedItem(null);
60 | mUiData.getSelectedMap().remove(key);
61 | }
62 | } else {
63 | entity.setStatus(entity.getStatus() == ProductModel.AttributeMemberStatus.UNCHECKABLE ? ProductModel.AttributeMemberStatus.UNCHECKABLE :
64 | ProductModel.AttributeMemberStatus.CHECKABLE);
65 | }
66 | }
67 | //存放当前被点击的按钮
68 | mUiData.getSelectedEntities().clear();
69 | for (int i = 0; i < mUiData.getAdapters().size(); i++) {
70 | if (mUiData.getAdapters().get(i).getCurrentSelectedItem() != null) {
71 | mUiData.getSelectedEntities().add(mUiData.getAdapters().get(i).getCurrentSelectedItem());
72 | }
73 | }
74 | //处理未选中的按钮
75 | for (int i = 0; i < mUiData.getAdapters().size(); i++) {
76 | for (ProductModel.AttributesEntity.AttributeMembersEntity entity : mUiData.getAdapters().get(i).getAttributeMembersEntities()) {
77 | // 处理没有数据和没有库存(检测单个)
78 | if (mUiData.getResult().get(entity.getAttributeMemberId() + "") == null || mUiData.getResult().get(entity.getAttributeMemberId() + "").getStock() <= 0) {
79 | entity.setStatus(ProductModel.AttributeMemberStatus.UNCHECKABLE);
80 | } else if (entity.equals(mUiData.getAdapters().get(i).getCurrentSelectedItem())) {
81 | entity.setStatus(ProductModel.AttributeMemberStatus.CHECKED);
82 | } else {
83 | entity.setStatus(ProductModel.AttributeMemberStatus.CHECKABLE);
84 | }
85 | // 冒泡排序
86 | List cacheSelected = new ArrayList<>();
87 | cacheSelected.add(entity);
88 | cacheSelected.addAll(mUiData.getSelectedEntities());
89 | for (int j = 0; j < cacheSelected.size() - 1; j++) {
90 | for (int k = 0; k < cacheSelected.size() - 1 - j; k++) {
91 | ProductModel.AttributesEntity.AttributeMembersEntity cacheEntity;
92 | if (cacheSelected.get(k).getAttributeGroupId() > cacheSelected.get(k + 1).getAttributeGroupId()) {
93 | //交换数据
94 | cacheEntity = cacheSelected.get(k);
95 | cacheSelected.set(k, cacheSelected.get(k + 1));
96 | cacheSelected.set(k + 1, cacheEntity);
97 | }
98 | }
99 | }
100 | for (int j = 0; j < cacheSelected.size() - 1; j++) {
101 | for (int k = 0; k < cacheSelected.size() - 1 - j; k++) {
102 | if (cacheSelected.get(k).getAttributeGroupId() == cacheSelected.get(k + 1).getAttributeGroupId()) {
103 | cacheSelected.remove(k + 1);
104 | }
105 | }
106 | }
107 | StringBuffer buffer = new StringBuffer();
108 | for (ProductModel.AttributesEntity.AttributeMembersEntity selectedEntity : cacheSelected) {
109 | buffer.append(selectedEntity.getAttributeMemberId() + ",");
110 | }
111 | // Log.e(TAG, "key = " + buffer.substring(0, buffer.length() - 1));
112 | //TODO 检查数据
113 | if (mUiData.getResult().get(buffer.substring(0, buffer.length() - 1)) != null && mUiData.getResult().get(buffer.substring(0, buffer.length() - 1)).getStock() > 0) {
114 | entity.setStatus(entity.getStatus() == ProductModel.AttributeMemberStatus.CHECKED ? ProductModel.AttributeMemberStatus.CHECKED :
115 | ProductModel.AttributeMemberStatus.CHECKABLE);
116 | } else {
117 | entity.setStatus(ProductModel.AttributeMemberStatus.UNCHECKABLE);
118 | }
119 | }
120 | mUiData.getAdapters().get(i).notifyDataSetChanged();
121 | }
122 |
123 | //规格提示
124 | StringBuilder tips = new StringBuilder();
125 | //specCmob
126 | StringBuilder specId = new StringBuilder();
127 | if (mUiData.getSelectedMap().size() == mUiData.getGroupNameList().size()) {
128 | //所有规格选择完了,展示价格 和 库存
129 | for (String groupName : mUiData.getGroupNameList()) {
130 | for (String k : mUiData.getSelectedMap().keySet()) {
131 | if (groupName.equals(k)) {
132 | tips.append(mUiData.getSelectedMap().get(k).getName()).append(" ");
133 | specId.append(mUiData.getSelectedMap().get(k).getAttributeMemberId()).append(",");
134 | }
135 | }
136 | }
137 | tips.insert(0, "已选 ");
138 | Log.d(TAG, "specId " + specId);
139 |
140 | ObserverHolder.getInstance().notifyObservers(specId.toString(), ObserverEventCode.SKU_GETSPECID);
141 | } else {
142 | for (String groupName : mUiData.getGroupNameList()) {
143 | if (!mUiData.getSelectedMap().keySet().contains(groupName))
144 | tips.append(groupName).append(" ");
145 | }
146 | tips.insert(0, "请选择 ");
147 | ObserverHolder.getInstance().notifyObservers("null", ObserverEventCode.SKU_GETSPECID);
148 | }
149 |
150 | ObserverHolder.getInstance().notifyObservers(tips.toString(), ObserverEventCode.SKU_TIPS);
151 |
152 |
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/sku/ProductModel.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.sku;
2 |
3 |
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | import io.github.wongxd.skulibray.specSelect.sku.skuLib.model.BaseSkuModel;
10 |
11 |
12 | public class ProductModel {
13 |
14 | //存储所有录入的库存情况
15 | private Map productStocks = new HashMap<>();
16 |
17 | //记录规格的种类
18 | private List attributes = new ArrayList<>();
19 |
20 | public Map getProductStocks() {
21 | return productStocks;
22 | }
23 |
24 | public void setProductStocks(Map productStocks) {
25 | this.productStocks = productStocks;
26 | }
27 |
28 | public List getAttributes() {
29 | return attributes;
30 | }
31 |
32 | public void setAttributes(List attributes) {
33 | this.attributes = attributes;
34 | }
35 |
36 | public enum AttributeMemberStatus {
37 | CHECKABLE , CHECKED, UNCHECKABLE
38 | }
39 |
40 | public static class AttributesEntity {
41 |
42 | private int id;
43 | private String name;
44 | private List attributeMembers = new ArrayList<>();
45 |
46 | public int getId() {
47 | return id;
48 | }
49 |
50 | public void setId(int id) {
51 | this.id = id;
52 | }
53 |
54 | public String getName() {
55 | return name;
56 | }
57 |
58 | public void setName(String name) {
59 | this.name = name;
60 | }
61 |
62 | public List getAttributeMembers() {
63 | return attributeMembers;
64 | }
65 |
66 | public void setAttributeMembers(List attributeMembers) {
67 | this.attributeMembers = attributeMembers;
68 | }
69 |
70 | public static class AttributeMembersEntity {
71 |
72 | private int attributeGroupId;
73 | private int attributeMemberId;
74 | private String name;
75 | private AttributeMemberStatus status;
76 |
77 | public AttributeMembersEntity(int attributeGroupId, int attributeMemberId, String name) {
78 | this.attributeGroupId = attributeGroupId;
79 | this.attributeMemberId = attributeMemberId;
80 | this.name = name;
81 | }
82 |
83 | @Override
84 | public boolean equals(Object obj) {
85 | if (!(obj instanceof AttributeMembersEntity))
86 | return false;
87 | AttributeMembersEntity entity = (AttributeMembersEntity) obj;
88 | return entity.getName().equals(name) && entity.getAttributeGroupId() == attributeGroupId && entity.getAttributeMemberId() == attributeMemberId;
89 | }
90 |
91 | public AttributeMemberStatus getStatus() {
92 | return status;
93 | }
94 |
95 | public void setStatus(AttributeMemberStatus status) {
96 | this.status = status;
97 | }
98 |
99 | public int getAttributeGroupId() {
100 | return attributeGroupId;
101 | }
102 |
103 | public void setAttributeGroupId(int attributeGroupId) {
104 | this.attributeGroupId = attributeGroupId;
105 | }
106 |
107 | public int getAttributeMemberId() {
108 | return attributeMemberId;
109 | }
110 |
111 | public void setAttributeMemberId(int attributeMemberId) {
112 | this.attributeMemberId = attributeMemberId;
113 | }
114 |
115 | public String getName() {
116 | return name;
117 | }
118 |
119 | public void setName(String name) {
120 | this.name = name;
121 | }
122 |
123 | }
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/sku/SkuAdapter.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.sku;
2 |
3 | import android.graphics.Color;
4 | import android.support.v7.widget.RecyclerView;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.TextView;
9 |
10 | import java.util.List;
11 |
12 | import io.github.wongxd.skulibray.R;
13 |
14 |
15 | public class SkuAdapter extends RecyclerView.Adapter {
16 |
17 | private List mAttributeMembersEntities;
18 | private OnClickListener mOnClickListener;
19 | private ProductModel.AttributesEntity.AttributeMembersEntity currentSelectedItem;
20 | String groupName;
21 |
22 |
23 | public SkuAdapter(List attributeMembersEntities, String groupName) {
24 | this.mAttributeMembersEntities = attributeMembersEntities;
25 | this.groupName = groupName;
26 | }
27 |
28 | public ProductModel.AttributesEntity.AttributeMembersEntity getCurrentSelectedItem() {
29 | return currentSelectedItem;
30 | }
31 |
32 | public void setCurrentSelectedItem(ProductModel.AttributesEntity.AttributeMembersEntity currentSelectedItem) {
33 | this.currentSelectedItem = currentSelectedItem;
34 | }
35 |
36 | public List getAttributeMembersEntities() {
37 | return mAttributeMembersEntities;
38 | }
39 |
40 | public OnClickListener getOnClickListener() {
41 | return mOnClickListener;
42 | }
43 |
44 | public void setOnClickListener(OnClickListener onClickListener) {
45 | mOnClickListener = onClickListener;
46 | }
47 |
48 | @Override
49 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
50 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.sku_item_layout, parent, false);
51 | return new ViewHolder(v);
52 | }
53 |
54 | @Override
55 | public void onBindViewHolder(ViewHolder holder, int position) {
56 | holder.setData(mAttributeMembersEntities.get(position));
57 | holder.setClick(position);
58 | }
59 |
60 | @Override
61 | public int getItemCount() {
62 | return mAttributeMembersEntities.size();
63 | }
64 |
65 | class ViewHolder extends RecyclerView.ViewHolder {
66 |
67 | private TextView mTextView;
68 |
69 | public ViewHolder(View itemView) {
70 | super(itemView);
71 | mTextView = (TextView) itemView.findViewById(R.id.tv);
72 | }
73 |
74 | public void setData(ProductModel.AttributesEntity.AttributeMembersEntity entity) {
75 | mTextView.setText(entity.getName());
76 | ProductModel.AttributeMemberStatus status = entity.getStatus();
77 | if (status == ProductModel.AttributeMemberStatus.CHECKED) {
78 | mTextView.setAlpha(1f);
79 | mTextView.setBackgroundResource(R.drawable.checked_bg);
80 | mTextView.setTextColor(Color.WHITE);
81 | } else if (status == ProductModel.AttributeMemberStatus.UNCHECKABLE) {
82 | mTextView.setAlpha(0.4f);
83 | mTextView.setBackgroundResource(R.drawable.unclickable_bg);
84 | mTextView.setTextColor(Color.BLACK);
85 | } else {
86 | mTextView.setAlpha(1f);
87 | mTextView.setBackgroundResource(R.drawable.normal_bg);
88 | mTextView.setTextColor(Color.BLACK);
89 | }
90 |
91 | }
92 |
93 | public void setClick(final int position) {
94 | mTextView.setOnClickListener(new View.OnClickListener() {
95 | @Override
96 | public void onClick(View v) {
97 | if (mOnClickListener != null)
98 | mOnClickListener.onItemClickListener(position);
99 | }
100 | });
101 | }
102 | }
103 |
104 | public interface OnClickListener {
105 | void onItemClickListener(int position);
106 |
107 | void onItemClickListener(ProductModel.AttributesEntity.AttributeMembersEntity attributeMembersEntity);
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/sku/UiData.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.sku;
2 |
3 |
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | import io.github.wongxd.skulibray.specSelect.sku.skuLib.model.BaseSkuModel;
10 |
11 |
12 | public class UiData {
13 |
14 | /**
15 | * 当前选择的规格组合
16 | */
17 |
18 | private Map selectedMap = new HashMap<>();
19 |
20 | public Map getSelectedMap() {
21 | return selectedMap;
22 | }
23 |
24 |
25 | /**
26 | * 所有规格 的 组名
27 | */
28 | private List groupNameList = new ArrayList();
29 |
30 | public List getGroupNameList() {
31 | return groupNameList;
32 | }
33 |
34 | public void setGroupNameList(List groupNameList) {
35 | this.groupNameList = groupNameList;
36 | }
37 |
38 |
39 | // 保存多组adapter
40 | private List adapters = new ArrayList<>();
41 |
42 | //存放被选中的按钮对应的数据
43 | private List selectedEntities = new ArrayList<>();
44 |
45 | //存放计算结果
46 | private Map result;
47 |
48 | public List getAdapters() {
49 | return adapters;
50 | }
51 |
52 |
53 | public Map getResult() {
54 | return result;
55 | }
56 |
57 | public void setResult(Map result) {
58 | this.result = result;
59 | }
60 |
61 |
62 | public List getSelectedEntities() {
63 | return selectedEntities;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/sku/skuLib/Sku.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.sku.skuLib;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.util.ArrayList;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | import io.github.wongxd.skulibray.specSelect.sku.skuLib.model.BaseSkuModel;
10 |
11 |
12 | /**
13 | * Sku算法
14 | */
15 |
16 | public class Sku {
17 |
18 | /**
19 | * 算法入口
20 | *
21 | * @param initData 所有库存的hashMap组合
22 | * @return 拆分所有组合产生的所有情况(生成客户端自己的字典)
23 | */
24 | public static Map skuCollection(Map initData) {
25 | //用户返回数据
26 | HashMap result = new HashMap<>();
27 | // 遍历所有库存
28 | for (String subKey : initData.keySet()) {
29 | BaseSkuModel skuModel = initData.get(subKey);
30 | //根据;拆分key的组合
31 | String[] skuKeyAttrs = subKey.split(",");
32 |
33 | //获取所有的组合
34 | ArrayList> combArr = combInArray(skuKeyAttrs);
35 |
36 | // 对应所有组合添加到结果集里面
37 | for (int i = 0; i < combArr.size(); i++) {
38 | add2SKUResult(result, combArr.get(i), skuModel);
39 | }
40 |
41 | // 将原始的库存组合也添加进入结果集里面
42 | String key = TextUtils.join(",", skuKeyAttrs);
43 | result.put(key, skuModel);
44 | }
45 | return result;
46 | }
47 |
48 | /**
49 | * 获取所有的组合放到ArrayList里面
50 | *
51 | * @param skuKeyAttrs 单个key被 , 拆分的数组
52 | * @return ArrayList
53 | */
54 | private static ArrayList> combInArray(String[] skuKeyAttrs) {
55 | if (skuKeyAttrs == null || skuKeyAttrs.length <= 0)
56 | return null;
57 | int len = skuKeyAttrs.length;
58 | ArrayList> aResult = new ArrayList<>();
59 | for (int n = 1; n < len; n++) {
60 | ArrayList aaFlags = getCombFlags(len, n);
61 | for (int i = 0; i < aaFlags.size(); i++) {
62 | Integer[] aFlag = aaFlags.get(i);
63 | ArrayList aComb = new ArrayList<>();
64 | for (int j = 0; j < aFlag.length; j++) {
65 | if (aFlag[j] == 1) {
66 | aComb.add(skuKeyAttrs[j]);
67 | }
68 | }
69 | aResult.add(aComb);
70 | }
71 | }
72 | return aResult;
73 | }
74 |
75 | /**
76 | * 算法拆分组合 用1和0 的移位去做控制
77 | * (这块需要你打印才能看的出来)
78 | *
79 | * @param len
80 | * @param n
81 | * @return
82 | */
83 | private static ArrayList getCombFlags(int len, int n) {
84 | if (n <= 0) {
85 | return new ArrayList<>();
86 | }
87 | ArrayList aResult = new ArrayList<>();
88 | Integer[] aFlag = new Integer[len];
89 | boolean bNext = true;
90 | int iCnt1 = 0;
91 | //初始化
92 | for (int i = 0; i < len; i++) {
93 | aFlag[i] = i < n ? 1 : 0;
94 | }
95 | aResult.add(aFlag.clone());
96 | while (bNext) {
97 | iCnt1 = 0;
98 | for (int i = 0; i < len - 1; i++) {
99 | if (aFlag[i] == 1 && aFlag[i + 1] == 0) {
100 | for (int j = 0; j < i; j++) {
101 | aFlag[j] = j < iCnt1 ? 1 : 0;
102 | }
103 | aFlag[i] = 0;
104 | aFlag[i + 1] = 1;
105 | Integer[] aTmp = aFlag.clone();
106 | aResult.add(aTmp);
107 | if (!TextUtils.join("", aTmp).substring(len - n).contains("0")) {
108 | bNext = false;
109 | }
110 | break;
111 | }
112 | if (aFlag[i] == 1) {
113 | iCnt1++;
114 | }
115 | }
116 | }
117 | return aResult;
118 | }
119 |
120 | /**
121 | * 添加到数据集合
122 | *
123 | * @param result
124 | * @param newKeyList
125 | * @param skuModel
126 | */
127 | private static void add2SKUResult(HashMap result, ArrayList newKeyList, BaseSkuModel skuModel) {
128 | String key = TextUtils.join(",", newKeyList);
129 | if (result.keySet().contains(key)) {
130 | result.get(key).setStock(result.get(key).getStock() + skuModel.getStock());
131 | result.get(key).setPrice(skuModel.getPrice());
132 | } else {
133 | result.put(key, new BaseSkuModel(skuModel.getPrice(), skuModel.getStock()));
134 | }
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/skulibray/src/main/java/io/github/wongxd/skulibray/specSelect/sku/skuLib/model/BaseSkuModel.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray.specSelect.sku.skuLib.model;
2 |
3 | /**
4 | * Sku
5 | *
6 | * Sku基本模型数据
7 | */
8 | public class BaseSkuModel {
9 |
10 | //base 属性
11 | private CharSequence price;//价格
12 | private int stock;//库存
13 |
14 | public BaseSkuModel() {
15 | }
16 |
17 | public BaseSkuModel(CharSequence price, int stock) {
18 | this.price = price;
19 | this.stock = stock;
20 | }
21 |
22 | public CharSequence getPrice() {
23 | return price;
24 | }
25 |
26 | public void setPrice(CharSequence price) {
27 | this.price = price;
28 | }
29 |
30 | public int getStock() {
31 | return stock;
32 | }
33 |
34 | public void setStock(int stock) {
35 | this.stock = stock;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/anim/bottomview_anim_enter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/anim/bottomview_anim_exit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/skulibray/src/main/res/drawable/add.png
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/check_un.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/skulibray/src/main/res/drawable/check_un.png
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/checked_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/skulibray/src/main/res/drawable/close.png
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/skulibray/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/normal_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/reduce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wongxd/skuLib/219bef5ff975fc2bf85c40a740c0f2129397f9a6/skulibray/src/main/res/drawable/reduce.png
--------------------------------------------------------------------------------
/skulibray/src/main/res/drawable/unclickable_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/layout/bottom_sheet_group.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
22 |
23 |
29 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/layout/fgt_spec_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
20 |
21 |
27 |
28 |
35 |
36 |
42 |
43 |
50 |
51 |
52 |
58 |
59 |
66 |
67 |
68 |
72 |
73 |
78 |
79 |
83 |
84 |
90 |
91 |
95 |
96 |
100 |
101 |
109 |
110 |
115 |
116 |
123 |
124 |
132 |
133 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
151 |
152 |
153 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/layout/sku_item_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #f1f1f1
4 | #ffffff
5 | #000000
6 | #854265
7 | #f5f5f5
8 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | skuLibray
3 |
4 |
--------------------------------------------------------------------------------
/skulibray/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/skulibray/src/test/java/io/github/wongxd/skulibray/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package io.github.wongxd.skulibray;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/testJson.txt:
--------------------------------------------------------------------------------
1 | {
2 | "attrs": [
3 | {
4 | "key": "颜色",
5 | "value": [
6 | {
7 | "id": 3,
8 | "name": "红色",
9 | "ownId": 1
10 | },
11 | {
12 | "id": 4,
13 | "name": "蓝色",
14 | "ownId": 1
15 | }
16 | ]
17 | },
18 | {
19 | "key": "重量",
20 | "value": [
21 | {
22 | "id": 5,
23 | "name": "10KG",
24 | "ownId": 2
25 | },
26 | {
27 | "id": 6,
28 | "name": "20KG",
29 | "ownId": 2
30 | },
31 | {
32 | "id": 7,
33 | "name": "30KG",
34 | "ownId": 2
35 | }
36 | ]
37 | },
38 | {
39 | "key": "产地",
40 | "value": [
41 | {
42 | "id": 24,
43 | "name": "江油",
44 | "ownId": 22
45 | },
46 | {
47 | "id": 23,
48 | "name": "绵阳",
49 | "ownId": 22
50 | },
51 | {
52 | "id": 31,
53 | "name": "四川绵阳市涪城区的撒啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊",
54 | "ownId": 22
55 | }
56 | ]
57 | },
58 | {
59 | "key": "尺寸",
60 | "value": [
61 | {
62 | "id": 20,
63 | "name": "30cm",
64 | "ownId": 14
65 | },
66 | {
67 | "id": 19,
68 | "name": "20cm",
69 | "ownId": 14
70 | },
71 | {
72 | "id": 18,
73 | "name": "10cm",
74 | "ownId": 14
75 | }
76 | ]
77 | }
78 | ],
79 | "combs": [
80 | {
81 | "comb": "4,6,23,20",
82 | "desc": "蓝色-20KG-绵阳-30cm",
83 | "id": 10,
84 | "price": 1.0,
85 | "productId": 5,
86 | "stock": 2,
87 | "specImg":"http://ww3.sinaimg.cn/mw600/0073ob6Pgy1fo91049t9mj30lc0w0dnh.jpg"
88 | },
89 | {
90 | "comb": "4,5,23,19",
91 | "desc": "蓝色-10KG-绵阳-20cm",
92 | "id": 8,
93 | "price": 22.0,
94 | "productId": 5,
95 | "stock": 333,
96 | "specImg":"http://wx4.sinaimg.cn/mw600/0072bW0Xly1fo908gkyqjj30en0miabp.jpg"
97 | },
98 | {
99 | "comb": "4,5,24,19",
100 | "desc": "蓝色-10KG-江油-20cm",
101 | "id": 9,
102 | "price": 1.0,
103 | "productId": 5,
104 | "stock": 2,
105 | "specImg":"http://wx1.sinaimg.cn/mw600/0072bW0Xly1fo8zz4znwyj30hq0qoabz.jpg"
106 | },
107 | {
108 | "comb": "3,6,24,18",
109 | "desc": "红色-20KG-江油-10",
110 | "id": 11,
111 | "price": 1.0,
112 | "productId": 5,
113 | "stock": 2,
114 | "specImg":"http://wx2.sinaimg.cn/mw600/0072bW0Xly1fo8zf0pn15j30ia0tzdox.jpg"
115 | }
116 | ]
117 | }
--------------------------------------------------------------------------------