├── README.md ├── android ├── MultiExpandableList │ ├── .gitignore │ ├── .idea │ │ ├── compiler.xml │ │ ├── copyright │ │ │ └── profiles_settings.xml │ │ ├── dictionaries │ │ │ └── fxp.xml │ │ ├── encodings.xml │ │ ├── gradle.xml │ │ ├── misc.xml │ │ ├── modules.xml │ │ └── runConfigurations.xml │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── fxp │ │ │ │ └── com │ │ │ │ └── multiexpandablelist │ │ │ │ └── ExampleInstrumentedTest.java │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── fxp │ │ │ │ │ └── com │ │ │ │ │ └── multiexpandablelist │ │ │ │ │ ├── activity │ │ │ │ │ └── MainActivity.java │ │ │ │ │ ├── adapter │ │ │ │ │ ├── ExpandableListViewAdapter.java │ │ │ │ │ ├── TagBaseAdapter.java │ │ │ │ │ └── TagCheckAdapter.java │ │ │ │ │ ├── bean │ │ │ │ │ ├── EquipmentInfo.java │ │ │ │ │ └── ItemInfo.java │ │ │ │ │ ├── entity │ │ │ │ │ ├── CheckItem.java │ │ │ │ │ └── TagCloudConfiguration.java │ │ │ │ │ ├── fxpInterface │ │ │ │ │ └── GetPictureListener.java │ │ │ │ │ └── view │ │ │ │ │ └── TagCloudLayout.java │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ ├── btn_bg.xml │ │ │ │ ├── edit_bg.xml │ │ │ │ ├── edit_focus_bg.xml │ │ │ │ ├── edit_unfocus_empty_bg.xml │ │ │ │ ├── tag_view.xml │ │ │ │ ├── tag_view_error.xml │ │ │ │ └── tag_view_ok.xml │ │ │ │ ├── layout │ │ │ │ ├── activity_main.xml │ │ │ │ ├── list_inner_edit_item.xml │ │ │ │ ├── list_inner_picture_item.xml │ │ │ │ ├── list_inner_select_item.xml │ │ │ │ ├── list_inner_text_item.xml │ │ │ │ ├── list_outer_item.xml │ │ │ │ └── list_tagview_item.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── camera_img.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── img.png │ │ │ │ ├── logo.jpg │ │ │ │ └── remark_img.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ │ ├── values │ │ │ │ ├── attrs.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ │ └── xml │ │ │ │ └── provider_paths.xml │ │ │ └── test │ │ │ └── java │ │ │ └── fxp │ │ │ └── com │ │ │ └── multiexpandablelist │ │ │ └── ExampleUnitTest.java │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle └── README.md └── web ├── .gitattributes ├── css └── expandable-list.css ├── data └── list.json ├── html ├── expandable-list.html └── list-item-tpl.html ├── images ├── .DS_Store ├── camera_img.png ├── img.png ├── item_remark_img.png └── logo.jpg ├── index.html ├── js ├── accordion.js └── expandable-list.js └── libs ├── framework7 ├── css │ ├── framework7.ios.colors.min.css │ ├── framework7.ios.min.css │ ├── framework7.material.colors.min.css │ ├── framework7.material.min.css │ └── my-app.css ├── img │ ├── i-f7-ios.png │ ├── i-f7-material.png │ ├── i-form-calendar-ios.svg │ ├── i-form-calendar-material.svg │ ├── i-form-comment-ios.svg │ ├── i-form-comment-material.svg │ ├── i-form-email-ios.svg │ ├── i-form-email-material.svg │ ├── i-form-gender-ios.svg │ ├── i-form-gender-material.svg │ ├── i-form-name-ios.svg │ ├── i-form-name-material.svg │ ├── i-form-password-ios.svg │ ├── i-form-password-material.svg │ ├── i-form-settings-ios.svg │ ├── i-form-settings-material.svg │ ├── i-form-tel-ios.svg │ ├── i-form-tel-material.svg │ ├── i-form-toggle-ios.svg │ ├── i-form-toggle-material.svg │ ├── i-form-url-ios.svg │ └── i-form-url-material.svg └── js │ ├── framework7.min.js │ └── init-app.js └── juicer-min.js /README.md: -------------------------------------------------------------------------------- 1 | # multi-expandable-list 2 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.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 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.idea/dictionaries/fxp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Java 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 62 | 63 | 64 | 65 | 66 | 67 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/MultiExpandableList/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "fxp.com.multiexpandablelist" 8 | minSdkVersion 14 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:26.0.0-alpha1' 28 | testCompile 'junit:junit:4.12' 29 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 30 | } 31 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/fxp/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/androidTest/java/fxp/com/multiexpandablelist/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("fxp.com.multiexpandablelist", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.activity; 2 | 3 | import android.Manifest; 4 | import android.annotation.TargetApi; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.pm.PackageManager; 8 | import android.net.Uri; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.os.Environment; 12 | import android.os.StrictMode; 13 | import android.provider.MediaStore; 14 | import android.support.annotation.NonNull; 15 | import android.support.annotation.RequiresApi; 16 | import android.support.v4.app.ActivityCompat; 17 | import android.support.v4.content.ContextCompat; 18 | import android.support.v4.content.FileProvider; 19 | import android.support.v7.app.AppCompatActivity; 20 | import android.util.Log; 21 | import android.widget.ExpandableListView; 22 | import android.widget.Toast; 23 | 24 | import java.io.File; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | import fxp.com.multiexpandablelist.R; 29 | import fxp.com.multiexpandablelist.adapter.ExpandableListViewAdapter; 30 | import fxp.com.multiexpandablelist.bean.EquipmentInfo; 31 | import fxp.com.multiexpandablelist.bean.ItemInfo; 32 | import fxp.com.multiexpandablelist.fxpInterface.GetPictureListener; 33 | 34 | public class MainActivity extends AppCompatActivity implements GetPictureListener { 35 | 36 | private String TAG = "MainActivity"; 37 | 38 | private Context context; 39 | 40 | private ExpandableListView expandableListView; 41 | 42 | private ExpandableListViewAdapter expandableListViewAdapter; 43 | 44 | private List groupList = null; 45 | 46 | private List> childrenList = null; 47 | 48 | public static final String IMAGE_PATH = "fxpFiles"; 49 | 50 | /* 相机请求码 */ 51 | private static final int REQUEST_CAMERA = 0; 52 | 53 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 54 | @Override 55 | protected void onCreate(Bundle savedInstanceState) { 56 | super.onCreate(savedInstanceState); 57 | setContentView(R.layout.activity_main); 58 | 59 | initDatas(); 60 | 61 | initViews(); 62 | 63 | initListeners(); 64 | 65 | // solveExceptionByVmPolicy(); 66 | } 67 | 68 | private void initDatas() { 69 | 70 | context = getApplicationContext(); 71 | 72 | getGroupListData(); 73 | 74 | getChildrenListData(); 75 | } 76 | 77 | private void initViews() { 78 | 79 | findViews(); 80 | 81 | initExpandableListView(); 82 | 83 | } 84 | 85 | private void initListeners() { 86 | expandableListViewAdapter.setGetPictureListener(this); 87 | } 88 | 89 | private void findViews() { 90 | expandableListView = (ExpandableListView) findViewById(R.id.expandable_lv); 91 | } 92 | 93 | /** 94 | * 初始化ExpandableListView 95 | */ 96 | private void initExpandableListView() { 97 | expandableListViewAdapter = new ExpandableListViewAdapter(context, groupList, childrenList); 98 | expandableListView.setAdapter(expandableListViewAdapter); 99 | expandableListView.setGroupIndicator(null); 100 | //设置默认为展开状态 101 | for (int i = 0; i < expandableListViewAdapter.getGroupCount(); i++) { 102 | expandableListView.expandGroup(i); 103 | } 104 | } 105 | 106 | /** 107 | * 模拟ExpandableListView一级列表数据 108 | */ 109 | private void getGroupListData() { 110 | groupList = new ArrayList(); 111 | for (int i = 0; i < 8; i++) { 112 | EquipmentInfo equipmentInfo = new EquipmentInfo(); 113 | equipmentInfo.setE_id("" + i); 114 | equipmentInfo.setE_name("小米电视A4"); 115 | groupList.add(i, equipmentInfo); 116 | } 117 | } 118 | 119 | /** 120 | * 模拟ExpandableListView二级列表数据 121 | */ 122 | private void getChildrenListData() { 123 | 124 | List itemInfos = new ArrayList(); 125 | 126 | ItemInfo itemInfo1 = new ItemInfo(); 127 | itemInfo1.setE_id("1"); 128 | itemInfo1.setI_id("1_0"); 129 | itemInfo1.setI_type("0"); 130 | itemInfo1.setI_name("机身温度"); 131 | itemInfo1.setI_increment("0.5"); 132 | itemInfo1.setI_reference("-10~60"); 133 | itemInfo1.setI_content(""); 134 | itemInfos.add(itemInfo1); 135 | 136 | ItemInfo itemInfo3 = new ItemInfo(); 137 | itemInfo3.setE_id("3"); 138 | itemInfo3.setI_id("3_1"); 139 | itemInfo3.setI_type("2"); 140 | itemInfo3.setI_name("画面色彩"); 141 | itemInfo3.setI_content(""); 142 | itemInfos.add(itemInfo3); 143 | 144 | ItemInfo itemInfo2 = new ItemInfo(); 145 | itemInfo2.setE_id("2"); 146 | itemInfo2.setI_id("2_1"); 147 | itemInfo2.setI_type("1"); 148 | itemInfo2.setI_name("播放内容"); 149 | itemInfo2.setI_content("海贼王万国篇-路飞VS卡二"); 150 | itemInfos.add(itemInfo2); 151 | 152 | ItemInfo itemInfo4 = new ItemInfo(); 153 | itemInfo4.setE_id("4"); 154 | itemInfo4.setI_id("4_1"); 155 | itemInfo4.setI_type("3"); 156 | itemInfo4.setI_name("体验评价"); 157 | itemInfo4.setI_content("播放流畅/音质很好/画质一般/屏幕反光/机身温度过高"); 158 | itemInfo4.setI_value("音质很好/机身温度过高"); 159 | itemInfos.add(itemInfo4); 160 | 161 | ItemInfo itemInfo5 = new ItemInfo(); 162 | itemInfo5.setE_id("5"); 163 | itemInfo5.setI_id("5_1"); 164 | itemInfo5.setI_type("4"); 165 | itemInfo5.setI_name("机身状况"); 166 | itemInfo5.setI_content(""); 167 | itemInfos.add(itemInfo5); 168 | 169 | childrenList = new ArrayList>(); 170 | for (int i = 0; i < 8; i++) { 171 | childrenList.add(itemInfos); 172 | } 173 | } 174 | 175 | @Override 176 | public void takePicture(int groupPosition, int childPosition) { 177 | Toast.makeText(context, "takePicture", Toast.LENGTH_SHORT).show(); 178 | 179 | //判断是否有权限 180 | if (hasPermission(Manifest.permission.CAMERA, Manifest.permission.CAMERA)) { 181 | //有权限 182 | takePhoto(); 183 | } else { 184 | //没权限,进行权限请求 185 | requestPermission(REQUEST_CAMERA, Manifest.permission.CAMERA); 186 | } 187 | } 188 | 189 | @Override 190 | public void selectPicture(int groupPosition, int childPosition) { 191 | Toast.makeText(context, "selectPicture", Toast.LENGTH_SHORT).show(); 192 | } 193 | 194 | @Override 195 | public void onActivityResult(int req, int res, Intent data) { 196 | switch (req) { 197 | case REQUEST_CAMERA: 198 | if (res == RESULT_OK) { 199 | Log.i(TAG, "拍照成功"); 200 | 201 | } else { 202 | Log.i(TAG, "拍照失败"); 203 | } 204 | break; 205 | default: 206 | break; 207 | } 208 | } 209 | 210 | /** 211 | * 调用系统相机拍照 212 | */ 213 | private void takePhoto() { 214 | String imgName = System.currentTimeMillis() + ".jpg"; 215 | Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); 216 | intent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoUri(IMAGE_PATH, imgName)); 217 | startActivityForResult(intent, REQUEST_CAMERA); 218 | } 219 | 220 | /** 221 | * 获取照片Uri 222 | * 223 | * @param path 保存照片文件夹名称 224 | * @param name 照片名称 225 | * @return 226 | */ 227 | private Uri getPhotoUri(String path, String name) { 228 | String sdStatus = Environment.getExternalStorageState(); 229 | if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { 230 | return null; 231 | } 232 | File file = new File(Environment.getExternalStorageDirectory(), path); 233 | if (!file.exists()) { 234 | file.mkdir(); 235 | } 236 | File output = new File(file, name); 237 | try { 238 | if (output.exists()) { 239 | output.delete(); 240 | } 241 | output.createNewFile(); 242 | } catch (Exception e) { 243 | e.printStackTrace(); 244 | } 245 | 246 | // 解决Android7.0相机权限问题方法1 - onCreate中调用solveExceptionByVmPolicy() 247 | // Uri photoURI = Uri.fromFile(output); 248 | 249 | // 解决Android7.0相机权限问题方法2 - FileProvider方式(谷歌官方推荐) 250 | Uri photoURI = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", output); 251 | 252 | return photoURI; 253 | } 254 | 255 | /** 256 | * 判断是否拥有权限 257 | * 258 | * @param permissions 形参String...的效果其实就和数组一样,这里的实参可以写多个String 259 | * @return 260 | */ 261 | public boolean hasPermission(String... permissions) { 262 | for (String permission : permissions) { 263 | if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) 264 | return false; 265 | } 266 | return true; 267 | } 268 | 269 | /** 270 | * 请求权限 271 | */ 272 | protected void requestPermission(int code, String... permissions) { 273 | ActivityCompat.requestPermissions(this, permissions, code); 274 | Toast.makeText(context, "如果拒绝授权,会导致应用无法正常使用", Toast.LENGTH_SHORT).show(); 275 | } 276 | 277 | /** 278 | * 申请权限的回调 279 | * 280 | * @param requestCode requestCode 281 | * @param permissions permissions 282 | * @param grantResults grantResults 多个权限一起返回 283 | */ 284 | @Override 285 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 286 | if (requestCode == REQUEST_CAMERA) { 287 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 288 | Log.i(TAG, "获取相机权限成功"); 289 | takePhoto(); 290 | } else { 291 | Log.i(TAG, "获取相机权限失败"); 292 | } 293 | } else { 294 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 295 | } 296 | } 297 | 298 | /** 299 | * android 7.0系统解决拍照的问题 300 | * Android 7.0开始,一个应用提供自身文件给其它应用使用时,如果给出一个file://格式的URI的话,应用会抛出FileUriExposedException 301 | * onCreate中调用此方法即可 302 | */ 303 | @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2) 304 | private void solveExceptionByVmPolicy() { 305 | StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); 306 | StrictMode.setVmPolicy(builder.build()); 307 | builder.detectFileUriExposure(); 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/adapter/ExpandableListViewAdapter.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.adapter; 2 | 3 | import android.content.Context; 4 | import android.text.Editable; 5 | import android.text.TextWatcher; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseExpandableListAdapter; 10 | import android.widget.EditText; 11 | import android.widget.ImageView; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import fxp.com.multiexpandablelist.R; 19 | import fxp.com.multiexpandablelist.bean.EquipmentInfo; 20 | import fxp.com.multiexpandablelist.bean.ItemInfo; 21 | import fxp.com.multiexpandablelist.entity.CheckItem; 22 | import fxp.com.multiexpandablelist.fxpInterface.GetPictureListener; 23 | import fxp.com.multiexpandablelist.view.TagCloudLayout; 24 | 25 | /** 26 | * ExpandableListView 适配器 27 | *

28 | * Created by fxp on 2018/3/2. 29 | */ 30 | 31 | public class ExpandableListViewAdapter extends BaseExpandableListAdapter { 32 | 33 | private Context context; 34 | 35 | private LayoutInflater mInflater; 36 | 37 | private List groupList; 38 | 39 | private List> childrenList; 40 | 41 | private final int EDITTYPE = 0; 42 | 43 | private final int TEXTTYPE = 1; 44 | 45 | private final int SELECTTYPE = 2; 46 | 47 | private final int CHECKTYPE = 3; 48 | 49 | private final int PICTYPE = 4; 50 | 51 | // 缓存单选型View选择结果,用于界面重绘后恢复选中状态 52 | private String itemState = ""; 53 | 54 | // 多选型View标签适配器 55 | private TagCheckAdapter tagCheckAdapter; 56 | 57 | // 多选型View标签列表 58 | private List checkItems = new ArrayList(); 59 | 60 | // 多选型View中标签选中状态,存储所有标签的选中状态 61 | private List selectState = new ArrayList(); 62 | 63 | private GetPictureListener getPictureListener = null; 64 | 65 | public ExpandableListViewAdapter(Context context, List groupList, List> childrenList) { 66 | this.context = context; 67 | this.groupList = groupList; 68 | this.childrenList = childrenList; 69 | } 70 | 71 | public void setGetPictureListener(GetPictureListener listener) { 72 | this.getPictureListener = listener; 73 | } 74 | 75 | @Override 76 | public int getGroupCount() { 77 | return groupList.size(); 78 | } 79 | 80 | @Override 81 | public long getGroupId(int i) { 82 | return i; 83 | } 84 | 85 | @Override 86 | public Object getGroup(int i) { 87 | return groupList.get(i); 88 | } 89 | 90 | @Override 91 | public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { 92 | GroupViewHolder holder; 93 | if (convertView == null) { 94 | holder = new GroupViewHolder(); 95 | mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 96 | convertView = mInflater.inflate(R.layout.list_outer_item, null); 97 | holder.lable = (TextView) convertView.findViewById(R.id.lable); 98 | convertView.setTag(holder); 99 | } else { 100 | holder = (GroupViewHolder) convertView.getTag(); 101 | } 102 | 103 | holder.lable.setText(groupList.get(groupPosition).getE_name()); 104 | return convertView; 105 | } 106 | 107 | @Override 108 | public int getChildType(int groupPosition, int childPosition) { 109 | return Integer.parseInt(childrenList.get(groupPosition).get(childPosition).getI_type()); 110 | } 111 | 112 | @Override 113 | public int getChildrenCount(int i) { 114 | return childrenList.get(i).size(); 115 | } 116 | 117 | @Override 118 | public Object getChild(int i, int i1) { 119 | return childrenList.get(i).get(i1); 120 | } 121 | 122 | @Override 123 | public long getChildId(int i, int i1) { 124 | return i1; 125 | } 126 | 127 | @Override 128 | public boolean hasStableIds() { 129 | return false; 130 | } 131 | 132 | @Override 133 | public boolean isChildSelectable(int i, int i1) { 134 | return false; 135 | } 136 | 137 | /** 138 | * 包含多种类型item布局时,必须重写此方法 139 | *

140 | * 注意:此处返回值必须大于或等于布局种类数,不然会报错FATAL EXCEPTION: main Process: fxp.com.multiexpandablelist, PID: 28232 141 | * java.lang.ArrayIndexOutOfBoundsException: length=2; index=2 142 | * at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:6902) 143 | * at android.widget.ListView.measureHeightOfChildren(ListView.java:1338) 144 | * at android.widget.ListView.onMeasure(ListView.java:1233) 145 | * 146 | * @return 子布局种类数目 147 | */ 148 | @Override 149 | public int getChildTypeCount() { 150 | return 6; 151 | } 152 | 153 | @Override 154 | public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { 155 | int type = getChildType(groupPosition, childPosition); 156 | switch (type) { 157 | //数值型 158 | case EDITTYPE: { 159 | convertView = setEditCell(convertView, groupPosition, childPosition); 160 | break; 161 | } 162 | //字符型 163 | case TEXTTYPE: { 164 | convertView = setTextCell(convertView, groupPosition, childPosition); 165 | break; 166 | } 167 | //单选型 168 | case SELECTTYPE: { 169 | convertView = setSelectCell(convertView, groupPosition, childPosition); 170 | break; 171 | } 172 | //复选型 173 | case CHECKTYPE: { 174 | convertView = setCheckCell(convertView, groupPosition, childPosition); 175 | break; 176 | } 177 | //拍照型 178 | case PICTYPE: { 179 | convertView = setPictureCell(convertView, groupPosition, childPosition); 180 | break; 181 | } 182 | default: 183 | break; 184 | } 185 | 186 | return convertView; 187 | } 188 | 189 | /** 190 | * 数值型View 191 | * 192 | * @param convertView 193 | * @param groupPosition 194 | * @param childPosition 195 | * @return 196 | */ 197 | private View setEditCell(View convertView, final int groupPosition, final int childPosition) { 198 | EditViewHolder editViewHolder = null; 199 | final EditText tsEditText; 200 | 201 | if (null != convertView) { 202 | ((LinearLayout) convertView).removeAllViews(); 203 | } 204 | 205 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 206 | convertView = inflater.inflate(R.layout.list_inner_edit_item, null); 207 | editViewHolder = new EditViewHolder(); 208 | editViewHolder.decrease = (TextView) convertView.findViewById(R.id.decrease_btn); 209 | editViewHolder.lable = (TextView) convertView.findViewById(R.id.lable); 210 | editViewHolder.value = (EditText) convertView.findViewById(R.id.value); 211 | editViewHolder.increase = (TextView) convertView.findViewById(R.id.increase_btn); 212 | 213 | tsEditText = (EditText) convertView.findViewById(R.id.value); 214 | 215 | ItemInfo itemInfo = childrenList.get(groupPosition).get(childPosition); 216 | editViewHolder.lable.setText(itemInfo.getI_name()); 217 | editViewHolder.decrease.setText("-" + itemInfo.getI_increment()); 218 | editViewHolder.value.setHint(itemInfo.getI_reference()); 219 | editViewHolder.increase.setText("+" + itemInfo.getI_increment()); 220 | 221 | //界面重绘后,让输入框显示重绘前输入的内容 222 | editViewHolder.value.setText(itemInfo.getI_content()); 223 | 224 | editViewHolder.value.addTextChangedListener(new TextWatcher() { 225 | @Override 226 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 227 | 228 | } 229 | 230 | @Override 231 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 232 | //将输入框中内容保存,界面重绘后,让输入框显示保存的内容 233 | childrenList.get(groupPosition).get(childPosition).setI_content(tsEditText.getText().toString()); 234 | } 235 | 236 | @Override 237 | public void afterTextChanged(Editable editable) { 238 | 239 | } 240 | }); 241 | 242 | return convertView; 243 | } 244 | 245 | /** 246 | * 字符型View 247 | * 248 | * @param convertView 249 | * @param groupPosition 250 | * @param childPosition 251 | * @return 252 | */ 253 | private View setTextCell(View convertView, final int groupPosition, final int childPosition) { 254 | TextViewHolder textViewHolder = null; 255 | final EditText tsEditText; 256 | 257 | if (null != convertView) { 258 | ((LinearLayout) convertView).removeAllViews(); 259 | } 260 | 261 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 262 | convertView = inflater.inflate(R.layout.list_inner_text_item, null); 263 | textViewHolder = new TextViewHolder(); 264 | textViewHolder.lable = (TextView) convertView.findViewById(R.id.lable); 265 | textViewHolder.value = (EditText) convertView.findViewById(R.id.value); 266 | 267 | tsEditText = (EditText) convertView.findViewById(R.id.value); 268 | 269 | textViewHolder.lable.setText(childrenList.get(groupPosition).get(childPosition).getI_name()); 270 | textViewHolder.value.setHint(""); 271 | //界面重绘后,让输入框显示重绘前输入的内容 272 | textViewHolder.value.setText(childrenList.get(groupPosition).get(childPosition).getI_content()); 273 | 274 | textViewHolder.value.addTextChangedListener(new TextWatcher() { 275 | @Override 276 | public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 277 | 278 | } 279 | 280 | @Override 281 | public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 282 | //将输入框中内容保存,界面重绘后,让输入框显示保存的内容 283 | childrenList.get(groupPosition).get(childPosition).setI_content(tsEditText.getText().toString()); 284 | } 285 | 286 | @Override 287 | public void afterTextChanged(Editable editable) { 288 | 289 | } 290 | }); 291 | 292 | return convertView; 293 | } 294 | 295 | /** 296 | * 单选型View 297 | * 298 | * @param convertView 299 | * @param groupPosition 300 | * @param childPosition 301 | * @return 302 | */ 303 | private View setSelectCell(View convertView, final int groupPosition, final int childPosition) { 304 | SelectViewHolder selectViewHolder = null; 305 | 306 | if (null != convertView) { 307 | ((LinearLayout) convertView).removeAllViews(); 308 | } 309 | 310 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 311 | convertView = inflater.inflate(R.layout.list_inner_select_item, null); 312 | 313 | selectViewHolder = new SelectViewHolder(); 314 | selectViewHolder.lable = (TextView) convertView.findViewById(R.id.lable); 315 | selectViewHolder.mContainer = (TagCloudLayout) convertView.findViewById(R.id.container); 316 | convertView.setTag(selectViewHolder); 317 | 318 | selectViewHolder.lable.setText(childrenList.get(groupPosition).get(childPosition).getI_name()); 319 | 320 | //获取选择值,用于界面重绘后显示重绘前状态 321 | itemState = childrenList.get(groupPosition).get(childPosition).getI_content(); 322 | 323 | List mList = new ArrayList<>(); 324 | mList.add(context.getResources().getString(R.string.commen)); 325 | mList.add(context.getResources().getString(R.string.error)); 326 | 327 | TagBaseAdapter mAdapter = new TagBaseAdapter(context, mList, itemState); 328 | selectViewHolder.mContainer.setAdapter(mAdapter); 329 | 330 | selectViewHolder.mContainer.setItemClickListener(new TagCloudLayout.TagItemClickListener() { 331 | @Override 332 | public void itemClick(int position) { 333 | // 保存状态,正常/异常 334 | if (position == 0) { 335 | itemState = context.getResources().getString(R.string.commen); 336 | childrenList.get(groupPosition).get(childPosition).setI_state(ItemInfo.STATE_CORRECT); 337 | } else if (position == 1) { 338 | itemState = context.getResources().getString(R.string.error); 339 | childrenList.get(groupPosition).get(childPosition).setI_state(ItemInfo.STATE_ERROR); 340 | } else { 341 | } 342 | 343 | // 刷新选中结果 344 | notifyDataSetInvalidated(); 345 | 346 | //保存选择值,用于界面重绘后显示重绘前状态 347 | childrenList.get(groupPosition).get(childPosition).setI_content(itemState); 348 | } 349 | }); 350 | 351 | return convertView; 352 | } 353 | 354 | 355 | /** 356 | * 复选型View 357 | * 358 | * @param convertView 359 | * @param groupPosition 360 | * @param childPosition 361 | * @return 362 | */ 363 | public View setCheckCell(View convertView, final int groupPosition, final int childPosition) { 364 | CheckViewHolder checkViewHolder = null; 365 | 366 | if (null != convertView) { 367 | ((LinearLayout) convertView).removeAllViews(); 368 | } 369 | 370 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 371 | convertView = inflater.inflate(R.layout.list_inner_select_item, null); 372 | checkViewHolder = new CheckViewHolder(); 373 | checkViewHolder.lable = (TextView) convertView.findViewById(R.id.lable); 374 | checkViewHolder.mContainer = (TagCloudLayout) convertView.findViewById(R.id.container); 375 | convertView.setTag(checkViewHolder); 376 | 377 | checkViewHolder.lable.setText(childrenList.get(groupPosition).get(childPosition).getI_name()); 378 | 379 | // 获取多选型View标签列表(过滤各标签选中状态) 380 | getTagList(childrenList.get(groupPosition).get(childPosition)); 381 | 382 | tagCheckAdapter = new TagCheckAdapter(context, checkItems); 383 | checkViewHolder.mContainer.setAdapter(tagCheckAdapter); 384 | checkViewHolder.mContainer.setItemClickListener(new TagCloudLayout.TagItemClickListener() { 385 | @Override 386 | public void itemClick(int position) { 387 | boolean isSelect = checkItems.get(position).isSelect(); 388 | if (isSelect) { 389 | checkItems.get(position).setIsSelect(false); 390 | tagCheckAdapter.setIsSelect(position, false); 391 | selectState.set(position, false); 392 | } else { 393 | checkItems.get(position).setIsSelect(true); 394 | tagCheckAdapter.setIsSelect(position, true); 395 | selectState.set(position, true); 396 | } 397 | 398 | // 刷新标签列表 399 | notifyDataSetInvalidated(); 400 | 401 | // 保存已选标签 402 | childrenList.get(groupPosition).get(childPosition).setI_value(getSelectedTags(checkItems)); 403 | } 404 | }); 405 | 406 | return convertView; 407 | } 408 | 409 | /** 410 | * 拍照型View 411 | * 412 | * @param convertView 413 | * @param groupPosition 414 | * @param childPosition 415 | * @return 416 | */ 417 | private View setPictureCell(View convertView, final int groupPosition, final int childPosition) { 418 | PicViewHolder picViewHolder = null; 419 | 420 | LayoutInflater inflater = LayoutInflater.from(context); 421 | convertView = inflater.inflate(R.layout.list_inner_picture_item, null); 422 | 423 | picViewHolder = new PicViewHolder(); 424 | picViewHolder.lable = (TextView) convertView.findViewById(R.id.lable); 425 | picViewHolder.takePicture = (TextView) convertView.findViewById(R.id.take_pic_btn); 426 | picViewHolder.selectPicure = (TextView) convertView.findViewById(R.id.select_pic_btn); 427 | 428 | convertView.setTag(picViewHolder); 429 | 430 | picViewHolder.lable.setText(childrenList.get(groupPosition).get(childPosition).getI_name()); 431 | picViewHolder.takePicture.setOnClickListener(new View.OnClickListener() { 432 | @Override 433 | public void onClick(View view) { 434 | getPictureListener.takePicture(groupPosition, childPosition); 435 | } 436 | }); 437 | picViewHolder.selectPicure.setOnClickListener(new View.OnClickListener() { 438 | @Override 439 | public void onClick(View view) { 440 | getPictureListener.selectPicture(groupPosition, childPosition); 441 | } 442 | }); 443 | 444 | return convertView; 445 | } 446 | 447 | class GroupViewHolder { 448 | private TextView lable; 449 | private ImageView stateIcon; 450 | } 451 | 452 | class EditViewHolder { 453 | private TextView decrease; 454 | private TextView lable; 455 | private EditText value; 456 | private TextView increase; 457 | } 458 | 459 | class TextViewHolder { 460 | private TextView lable; 461 | private EditText value; 462 | } 463 | 464 | class SelectViewHolder { 465 | TextView lable; 466 | TagCloudLayout mContainer; 467 | } 468 | 469 | class CheckViewHolder { 470 | TextView lable; 471 | TagCloudLayout mContainer; 472 | } 473 | 474 | class PicViewHolder { 475 | TextView lable; 476 | TextView takePicture; 477 | TextView selectPicure; 478 | } 479 | 480 | /** 481 | * 多选型View - 获取标签列表(过滤各标签选中状态) 482 | * 483 | * @param itemInfo 当前item项 484 | */ 485 | private void getTagList(ItemInfo itemInfo) { 486 | 487 | // 分割i_content,获取到标签数组lableStates 488 | String i_content = itemInfo.getI_content(); 489 | String lableStates[] = null; 490 | if (i_content != null && !i_content.equals("")) { 491 | lableStates = i_content.split("/"); 492 | } 493 | 494 | // 分割i_value,获取已选标签数组i_values 495 | String i_value = itemInfo.getI_value(); 496 | String i_values[] = null; 497 | if (i_value != null && !i_value.equals("")) { 498 | i_values = i_value.split("/"); 499 | } 500 | 501 | // 获取所有标签选中状态 502 | if (selectState.size() == 0) { 503 | // 遍历所有标签,获取标签选中状态 504 | for (int i = 0; i < lableStates.length; i++) { 505 | // 匹配flag 506 | boolean match = false; 507 | // 存在已选中的标签 508 | if (i_values != null) { 509 | // 遍历已选中标签,与当前标签lableStates[i]匹配 510 | for (int j = 0; j < i_values.length; j++) { 511 | // 当前标签lableStates[i]已被选中 512 | if (i_values[j].equals(lableStates[i])) { 513 | selectState.add(true); 514 | match = true; 515 | break; 516 | } 517 | } 518 | } 519 | if (!match) { 520 | // 当前标签lableStates[i]已被选中 521 | selectState.add(false); 522 | } 523 | } 524 | } 525 | 526 | // 清空标签列表 527 | checkItems.clear(); 528 | 529 | // 组装标签列表 530 | for (int i = 0; i < lableStates.length; i++) { 531 | CheckItem checkItem = new CheckItem(); 532 | checkItem.setItemLable(lableStates[i]); 533 | checkItem.setIsSelect(selectState.get(i)); 534 | checkItems.add(i, checkItem); 535 | } 536 | } 537 | 538 | /** 539 | * 多选型View - 获取已选标签 540 | * 541 | * @param items 标签列表 542 | * @return 已选标签拼接字符串 543 | */ 544 | private String getSelectedTags(List items) { 545 | String tags = ""; 546 | for (int i = 0; i < items.size(); i++) { 547 | if (items.get(i).isSelect()) { 548 | if (tags.trim().equals("") || tags == null) { 549 | tags = tags + items.get(i).getItemLable(); 550 | } else { 551 | tags = tags + "/" + items.get(i).getItemLable(); 552 | } 553 | } 554 | } 555 | return tags; 556 | } 557 | 558 | } 559 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/adapter/TagBaseAdapter.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.adapter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | import android.widget.TextView; 11 | 12 | import java.util.List; 13 | 14 | import fxp.com.multiexpandablelist.R; 15 | 16 | /** 17 | * 单选型View - 选项适配器 18 | *

19 | * Created by fxp on 2018/3/3. 20 | */ 21 | 22 | public class TagBaseAdapter extends BaseAdapter { 23 | 24 | private Context mContext; 25 | 26 | // 选项列表 27 | private List mList; 28 | 29 | // 当前选中状态 30 | private String itemState; 31 | 32 | public TagBaseAdapter(Context context, List list, String itemState) { 33 | this.mContext = context; 34 | this.mList = list; 35 | this.itemState = itemState; 36 | } 37 | 38 | public void setItemState(String itemState) { 39 | this.itemState = itemState; 40 | notifyDataSetChanged(); 41 | } 42 | 43 | @Override 44 | public int getCount() { 45 | return mList.size(); 46 | } 47 | 48 | @Override 49 | public String getItem(int position) { 50 | return mList.get(position); 51 | } 52 | 53 | @Override 54 | public long getItemId(int position) { 55 | return position; 56 | } 57 | 58 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 59 | @Override 60 | public View getView(int position, View convertView, ViewGroup parent) { 61 | ViewHolder holder; 62 | if (convertView == null) { 63 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_tagview_item, null); 64 | holder = new ViewHolder(); 65 | holder.tagBtn = (TextView) convertView.findViewById(R.id.tag_btn); 66 | convertView.setTag(holder); 67 | } else { 68 | holder = (ViewHolder) convertView.getTag(); 69 | } 70 | holder.tagBtn.setText(getItem(position)); 71 | 72 | if (position == 0 && itemState.equals("正常")) { 73 | holder.tagBtn.setTextColor(mContext.getResources().getColor(R.color.state_ok)); 74 | holder.tagBtn.setBackground(mContext.getResources().getDrawable(R.drawable.tag_view_ok)); 75 | } else if (position == 1 && itemState.equals("异常")) { 76 | holder.tagBtn.setTextColor(mContext.getResources().getColor(R.color.state_error)); 77 | holder.tagBtn.setBackground(mContext.getResources().getDrawable(R.drawable.tag_view_error)); 78 | } else { 79 | holder.tagBtn.setTextColor(mContext.getResources().getColor(R.color.light_gray)); 80 | holder.tagBtn.setBackground(mContext.getResources().getDrawable(R.drawable.tag_view)); 81 | } 82 | 83 | return convertView; 84 | } 85 | 86 | static class ViewHolder { 87 | TextView tagBtn; 88 | } 89 | } -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/adapter/TagCheckAdapter.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.adapter; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | import android.widget.TextView; 11 | 12 | import java.util.List; 13 | 14 | import fxp.com.multiexpandablelist.R; 15 | import fxp.com.multiexpandablelist.entity.CheckItem; 16 | 17 | /** 18 | * 多选型View - 选项适配器 19 | *

20 | * Created by fxp on 2018/3/3. 21 | */ 22 | public class TagCheckAdapter extends BaseAdapter { 23 | 24 | private Context mContext; 25 | 26 | private List checkItems; 27 | 28 | // boolean isSelect = false; 29 | 30 | 31 | public TagCheckAdapter(Context context, List checkItems) { 32 | this.mContext = context; 33 | this.checkItems = checkItems; 34 | } 35 | 36 | @Override 37 | public int getCount() { 38 | return checkItems.size(); 39 | } 40 | 41 | @Override 42 | public CheckItem getItem(int position) { 43 | return checkItems.get(position); 44 | } 45 | 46 | @Override 47 | public long getItemId(int position) { 48 | return position; 49 | } 50 | 51 | public void setIsSelect(int position, boolean isSelect) { 52 | checkItems.get(position).setIsSelect(isSelect); 53 | } 54 | 55 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 56 | @Override 57 | public View getView(int position, View convertView, ViewGroup parent) { 58 | ViewHolder holder; 59 | if (convertView == null) { 60 | convertView = LayoutInflater.from(mContext).inflate(R.layout.list_tagview_item, null); 61 | holder = new ViewHolder(); 62 | holder.tagBtn = (TextView) convertView.findViewById(R.id.tag_btn); 63 | convertView.setTag(holder); 64 | } else { 65 | holder = (ViewHolder) convertView.getTag(); 66 | } 67 | holder.tagBtn.setText(checkItems.get(position).getItemLable()); 68 | 69 | boolean isSelect = checkItems.get(position).isSelect(); 70 | if (isSelect) { 71 | holder.tagBtn.setTextColor(mContext.getResources().getColor(R.color.state_ok)); 72 | holder.tagBtn.setBackground(mContext.getResources().getDrawable(R.drawable.tag_view_ok)); 73 | } else { 74 | holder.tagBtn.setTextColor(mContext.getResources().getColor(R.color.light_gray)); 75 | holder.tagBtn.setBackground(mContext.getResources().getDrawable(R.drawable.tag_view)); 76 | } 77 | return convertView; 78 | } 79 | 80 | static class ViewHolder { 81 | TextView tagBtn; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/bean/EquipmentInfo.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.bean; 2 | 3 | /** 4 | * 5 | * 设备实体类 6 | * 7 | * Created by fxp on 2018/3/2. 8 | */ 9 | 10 | public class EquipmentInfo { 11 | 12 | private String e_id; 13 | 14 | private int e_index; 15 | 16 | private String e_name; 17 | 18 | private String e_state; 19 | 20 | private String e_remark; 21 | 22 | public String getE_id() { 23 | return e_id; 24 | } 25 | 26 | public void setE_id(String e_id) { 27 | this.e_id = e_id; 28 | } 29 | 30 | public int getE_index() { 31 | return e_index; 32 | } 33 | 34 | public void setE_index(int e_index) { 35 | this.e_index = e_index; 36 | } 37 | 38 | public String getE_name() { 39 | return e_name; 40 | } 41 | 42 | public void setE_name(String e_name) { 43 | this.e_name = e_name; 44 | } 45 | 46 | public String getE_state() { 47 | return e_state; 48 | } 49 | 50 | public void setE_state(String e_state) { 51 | this.e_state = e_state; 52 | } 53 | 54 | public String getE_remark() { 55 | return e_remark; 56 | } 57 | 58 | public void setE_remark(String e_remark) { 59 | this.e_remark = e_remark; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return "EquipmentInfo{" + 65 | "e_id='" + e_id + '\'' + 66 | ", e_index=" + e_index + 67 | ", e_name='" + e_name + '\'' + 68 | ", e_state='" + e_state + '\'' + 69 | ", e_remark='" + e_remark + '\'' + 70 | '}'; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/bean/ItemInfo.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.bean; 2 | 3 | /** 4 | * 设备参数实体类 5 | *

6 | * Created by fxp on 2018/3/2. 7 | */ 8 | 9 | public class ItemInfo { 10 | 11 | public static String STATE_CORRECT = "0"; 12 | 13 | public static String STATE_ERROR = "1"; 14 | 15 | private String i_id; 16 | 17 | private String e_id; 18 | 19 | private String i_index; 20 | 21 | private String i_name; 22 | 23 | private String i_type; 24 | 25 | private String i_value; 26 | 27 | private String i_state; 28 | 29 | private String i_reference; 30 | 31 | private String i_content; 32 | 33 | private String i_content_time; 34 | 35 | private String i_remark; 36 | 37 | private String i_increment; 38 | 39 | private String i_unit; 40 | 41 | public String getI_unit() { 42 | return i_unit; 43 | } 44 | 45 | public void setI_unit(String i_unit) { 46 | this.i_unit = i_unit; 47 | } 48 | 49 | public String getI_id() { 50 | return i_id; 51 | } 52 | 53 | public void setI_id(String i_id) { 54 | this.i_id = i_id; 55 | } 56 | 57 | public String getE_id() { 58 | return e_id; 59 | } 60 | 61 | public void setE_id(String e_id) { 62 | this.e_id = e_id; 63 | } 64 | 65 | public String getI_index() { 66 | return i_index; 67 | } 68 | 69 | public void setI_index(String i_index) { 70 | this.i_index = i_index; 71 | } 72 | 73 | public String getI_name() { 74 | return i_name; 75 | } 76 | 77 | public void setI_name(String i_name) { 78 | this.i_name = i_name; 79 | } 80 | 81 | public String getI_type() { 82 | return i_type; 83 | } 84 | 85 | public void setI_type(String i_type) { 86 | this.i_type = i_type; 87 | } 88 | 89 | public String getI_value() { 90 | return i_value; 91 | } 92 | 93 | public void setI_value(String i_value) { 94 | this.i_value = i_value; 95 | } 96 | 97 | public String getI_state() { 98 | return i_state; 99 | } 100 | 101 | public void setI_state(String i_state) { 102 | this.i_state = i_state; 103 | } 104 | 105 | public String getI_reference() { 106 | return i_reference; 107 | } 108 | 109 | public void setI_reference(String i_reference) { 110 | this.i_reference = i_reference; 111 | } 112 | 113 | public String getI_content() { 114 | return i_content; 115 | } 116 | 117 | public void setI_content(String i_content) { 118 | this.i_content = i_content; 119 | } 120 | 121 | public String getI_content_time() { 122 | return i_content_time; 123 | } 124 | 125 | public void setI_content_time(String i_content_time) { 126 | this.i_content_time = i_content_time; 127 | } 128 | 129 | public String getI_remark() { 130 | return i_remark; 131 | } 132 | 133 | public void setI_remark(String i_remark) { 134 | this.i_remark = i_remark; 135 | } 136 | 137 | public String getI_increment() { 138 | return i_increment; 139 | } 140 | 141 | public void setI_increment(String i_increment) { 142 | this.i_increment = i_increment; 143 | } 144 | 145 | @Override 146 | public String toString() { 147 | return "ItemInfo{" + 148 | "i_id='" + i_id + '\'' + 149 | ", e_id='" + e_id + '\'' + 150 | ", i_index='" + i_index + '\'' + 151 | ", i_name='" + i_name + '\'' + 152 | ", i_type='" + i_type + '\'' + 153 | ", i_value='" + i_value + '\'' + 154 | ", i_state='" + i_state + '\'' + 155 | ", i_reference='" + i_reference + '\'' + 156 | ", i_content='" + i_content + '\'' + 157 | ", i_content_time='" + i_content_time + '\'' + 158 | ", i_remark='" + i_remark + '\'' + 159 | ", i_increment='" + i_increment + '\'' + 160 | ", i_unit='" + i_unit + '\'' + 161 | '}'; 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/entity/CheckItem.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.entity; 2 | 3 | /** 4 | * 多选型View - 标签entity 5 | *

6 | * Created by fxp on 2018/3/3. 7 | */ 8 | 9 | public class CheckItem { 10 | 11 | private int ITEM_NORMAL = 0; 12 | 13 | private int ITEM_ERROR = 1; 14 | 15 | private int ITEM_NOTCHECK = 2; 16 | 17 | private String itemLable = null; 18 | 19 | private int itemState = 2; 20 | 21 | private boolean isSelect = true; 22 | 23 | public int getItemState() { 24 | return itemState; 25 | } 26 | 27 | public void setItemState(int itemState) { 28 | this.itemState = itemState; 29 | } 30 | 31 | public String getItemLable() { 32 | return itemLable; 33 | } 34 | 35 | public void setItemLable(String itemLable) { 36 | this.itemLable = itemLable; 37 | } 38 | 39 | public boolean isSelect() { 40 | return isSelect; 41 | } 42 | 43 | public void setIsSelect(boolean isSelect) { 44 | this.isSelect = isSelect; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/entity/TagCloudConfiguration.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.entity; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.util.AttributeSet; 6 | 7 | import fxp.com.multiexpandablelist.R; 8 | 9 | /** 10 | * @author fyales 11 | * @since date 11/3/15 12 | */ 13 | public class TagCloudConfiguration { 14 | 15 | private static final int DEFAULT_LINE_SPACING = 5; 16 | private static final int DEFAULT_TAG_SPACING = 10; 17 | private static final int DEFAULT_FIXED_COLUMN_SIZE = 3; //默认列数 18 | 19 | private int lineSpacing; 20 | private int tagSpacing; 21 | private int columnSize; 22 | private boolean isFixed; 23 | 24 | public TagCloudConfiguration(Context context, AttributeSet attrs) { 25 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TagCloudLayout); 26 | try { 27 | lineSpacing = a.getDimensionPixelSize(R.styleable.TagCloudLayout_lineSpacing, DEFAULT_LINE_SPACING); 28 | tagSpacing = a.getDimensionPixelSize(R.styleable.TagCloudLayout_tagSpacing, DEFAULT_TAG_SPACING); 29 | columnSize = a.getInteger(R.styleable.TagCloudLayout_columnSize, DEFAULT_FIXED_COLUMN_SIZE); 30 | isFixed = a.getBoolean(R.styleable.TagCloudLayout_isFixed, false); 31 | } finally { 32 | a.recycle(); 33 | } 34 | } 35 | 36 | public int getLineSpacing() { 37 | return lineSpacing; 38 | } 39 | 40 | public void setLineSpacing(int lineSpacing) { 41 | this.lineSpacing = lineSpacing; 42 | } 43 | 44 | public int getTagSpacing() { 45 | return tagSpacing; 46 | } 47 | 48 | public void setTagSpacing(int tagSpacing) { 49 | this.tagSpacing = tagSpacing; 50 | } 51 | 52 | public int getColumnSize() { 53 | return columnSize; 54 | } 55 | 56 | public void setColumnSize(int columnSize) { 57 | this.columnSize = columnSize; 58 | } 59 | 60 | public boolean isFixed() { 61 | return isFixed; 62 | } 63 | 64 | public void setIsFixed(boolean isFixed) { 65 | this.isFixed = isFixed; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/fxpInterface/GetPictureListener.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.fxpInterface; 2 | 3 | /** 4 | * 获取照片接口 5 | *

6 | * Created by fxp on 2018/3/4. 7 | */ 8 | 9 | public interface GetPictureListener { 10 | 11 | // 拍照 12 | void takePicture(int groupPosition, int childPosition); 13 | 14 | // 从相册获取照片F 15 | void selectPicture(int groupPosition, int childPosition); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/java/fxp/com/multiexpandablelist/view/TagCloudLayout.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist.view; 2 | 3 | import android.content.Context; 4 | import android.database.DataSetObserver; 5 | import android.graphics.Canvas; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | 11 | import fxp.com.multiexpandablelist.entity.TagCloudConfiguration; 12 | 13 | /** 14 | * 标签流容器 15 | * 16 | * @author fyales 17 | * @since date 2015-03-04 18 | */ 19 | public class TagCloudLayout extends ViewGroup { 20 | 21 | private int mLineSpacing; 22 | private int mTagSpacing; 23 | private BaseAdapter mAdapter; 24 | private TagItemClickListener mListener; 25 | private DataChangeObserver mObserver; 26 | 27 | public TagCloudLayout(Context context) { 28 | super(context); 29 | init(context, null, 0); 30 | } 31 | 32 | public TagCloudLayout(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | init(context, attrs, 0); 35 | } 36 | 37 | public TagCloudLayout(Context context, AttributeSet attrs, int defStyle) { 38 | super(context, attrs, defStyle); 39 | init(context, attrs, defStyle); 40 | } 41 | 42 | private void init(Context context, AttributeSet attrs, int defStyle) { 43 | TagCloudConfiguration config = new TagCloudConfiguration(context, attrs); 44 | mLineSpacing = config.getLineSpacing(); 45 | mTagSpacing = config.getTagSpacing(); 46 | } 47 | 48 | private void drawLayout() { 49 | if (mAdapter == null || mAdapter.getCount() == 0) { 50 | return; 51 | } 52 | 53 | this.removeAllViews(); 54 | 55 | for (int i = 0; i < mAdapter.getCount(); i++) { 56 | View view = mAdapter.getView(i,null,null); 57 | final int position = i; 58 | view.setOnClickListener(new OnClickListener() { 59 | @Override 60 | public void onClick(View v) { 61 | if (mListener != null) { 62 | mListener.itemClick(position); 63 | } 64 | } 65 | }); 66 | this.addView(view); 67 | } 68 | } 69 | 70 | @Override 71 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 72 | int wantHeight = 0; 73 | int wantWidth = resolveSize(0, widthMeasureSpec); 74 | int paddingLeft = getPaddingLeft(); 75 | int paddingRight = getPaddingRight(); 76 | int paddingTop = getPaddingTop(); 77 | int paddingBottom = getPaddingBottom(); 78 | int childLeft = paddingLeft; 79 | int childTop = paddingTop; 80 | int lineHeight = 0; 81 | 82 | for (int i = 0; i < getChildCount(); i++) { 83 | final View childView = getChildAt(i); 84 | LayoutParams params = childView.getLayoutParams(); 85 | childView.measure( 86 | getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, params.width), 87 | getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom, params.height) 88 | ); 89 | int childHeight = childView.getMeasuredHeight(); 90 | int childWidth = childView.getMeasuredWidth(); 91 | lineHeight = Math.max(childHeight, lineHeight); 92 | 93 | if (childLeft + childWidth + paddingRight > wantWidth) { 94 | childLeft = paddingLeft; 95 | childTop += mLineSpacing + childHeight; 96 | lineHeight = childHeight; 97 | } 98 | 99 | childLeft += childWidth + mTagSpacing; 100 | } 101 | wantHeight += childTop + lineHeight + paddingBottom; 102 | setMeasuredDimension(wantWidth, resolveSize(wantHeight, heightMeasureSpec)); 103 | } 104 | 105 | @Override 106 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 107 | int width = r - l; 108 | int paddingLeft = getPaddingLeft(); 109 | int paddingTop = getPaddingTop(); 110 | int paddingRight = getPaddingRight(); 111 | int childLeft = paddingLeft; 112 | int childTop = paddingTop; 113 | int lineHeight = 0; 114 | 115 | for (int i = 0; i < getChildCount(); i++) { 116 | final View childView = getChildAt(i); 117 | if (childView.getVisibility() == View.GONE) { 118 | continue; 119 | } 120 | int childWidth = childView.getMeasuredWidth(); 121 | int childHeight = childView.getMeasuredHeight(); 122 | lineHeight = Math.max(childHeight, lineHeight); 123 | 124 | if (childLeft + childWidth + paddingRight > width) { 125 | childLeft = paddingLeft; 126 | childTop += mLineSpacing + lineHeight; 127 | lineHeight = childHeight; 128 | } 129 | 130 | childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight); 131 | childLeft += childWidth + mTagSpacing; 132 | } 133 | } 134 | 135 | @Override 136 | protected void onDraw(Canvas canvas) { 137 | super.onDraw(canvas); 138 | } 139 | 140 | @Override 141 | public LayoutParams generateLayoutParams(AttributeSet attrs) { 142 | return new LayoutParams(this.getContext(), attrs); 143 | } 144 | 145 | public void setAdapter(BaseAdapter adapter){ 146 | if (mAdapter == null){ 147 | mAdapter = adapter; 148 | if (mObserver == null){ 149 | mObserver = new DataChangeObserver(); 150 | mAdapter.registerDataSetObserver(mObserver); 151 | } 152 | drawLayout(); 153 | } 154 | } 155 | 156 | public void setItemClickListener(TagItemClickListener mListener) { 157 | this.mListener = mListener; 158 | } 159 | 160 | public interface TagItemClickListener { 161 | void itemClick(int position); 162 | } 163 | 164 | class DataChangeObserver extends DataSetObserver { 165 | @Override 166 | public void onChanged() { 167 | TagCloudLayout.this.drawLayout(); 168 | } 169 | 170 | @Override 171 | public void onInvalidated() { 172 | super.onInvalidated(); 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/drawable/btn_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/drawable/edit_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/drawable/edit_focus_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/drawable/edit_unfocus_empty_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/drawable/tag_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/drawable/tag_view_error.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/drawable/tag_view_ok.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/layout/list_inner_edit_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 17 | 18 | 24 | 25 | 38 | 39 | 52 | 53 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/layout/list_inner_picture_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 18 | 19 | 24 | 25 | 41 | 42 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/layout/list_inner_select_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 31 | 32 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/layout/list_inner_text_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 18 | 19 | 31 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/layout/list_outer_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 18 | 19 | 27 | 28 | 33 | 34 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/layout/list_tagview_item.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/camera_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/camera_img.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/img.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/logo.jpg -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/remark_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-xxhdpi/remark_img.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | 5 | #303F9F 6 | 7 | #FF4081 8 | 9 | /** 白色 **/ 10 | #ffffff 11 | 12 | /** 黑色 **/ 13 | #ff000000 14 | 15 | #CECECE 16 | 17 | #FF673E 18 | 19 | #FF673E 20 | 21 | #FFCDD2 22 | 23 | 24 | #00000000 25 | 26 | #DADADA 27 | 28 | #A0C2FF 29 | 30 | #BDC0C2 31 | 32 | #5D6368 33 | 34 | #7CACFF 35 | 36 | #FB5741 37 | 38 | 39 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MultiExpandableList 3 | 正常 4 | 异常 5 | 6 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/main/res/xml/provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /android/MultiExpandableList/app/src/test/java/fxp/com/multiexpandablelist/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package fxp.com.multiexpandablelist; 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 | } -------------------------------------------------------------------------------- /android/MultiExpandableList/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /android/MultiExpandableList/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 | -------------------------------------------------------------------------------- /android/MultiExpandableList/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/android/MultiExpandableList/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/MultiExpandableList/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /android/MultiExpandableList/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 | -------------------------------------------------------------------------------- /android/MultiExpandableList/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 | -------------------------------------------------------------------------------- /android/MultiExpandableList/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /android/README.md: -------------------------------------------------------------------------------- 1 | # multi-expandable-list (Android版本) 2 | -------------------------------------------------------------------------------- /web/.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-language=javascript -------------------------------------------------------------------------------- /web/css/expandable-list.css: -------------------------------------------------------------------------------- 1 | .theme-bg{ 2 | background-color: #057BDD; 3 | } 4 | 5 | .theme-color{ 6 | color: #057BDD; 7 | } 8 | 9 | .theme-border { 10 | border: 1px solid #057BDD !important; 11 | } 12 | 13 | .txt-overflow{ 14 | white-space:nowrap; 15 | overflow:hidden; 16 | text-overflow:ellipsis; 17 | } 18 | 19 | .accordion_item_li { 20 | border-top: 1px solid #dbdbdb; 21 | border-bottom: 1px solid #dbdbdb; 22 | } 23 | 24 | .accordion_outer_equip_name{ 25 | float: left; 26 | width: 60%; 27 | margin-top: 0.5rem; 28 | font-size: 1.2rem; 29 | color: black; 30 | } 31 | 32 | .accordion_outer_remark_icon{ 33 | float: right; 34 | margin-right: 1rem; 35 | width: 2rem; 36 | margin-top: 0.2rem; 37 | } 38 | 39 | .accordion_inner_item_name{ 40 | height: 100%; 41 | width: 35%; 42 | height: 2.5rem; 43 | float: left; 44 | padding: 0.5rem 0.2rem 0.5rem 0.2rem; 45 | font-size: 1rem; 46 | } 47 | 48 | .num_item_increment{ 49 | text-align: center; 50 | width: 2.5rem; 51 | float: left; 52 | margin: 0.5rem 0.15rem; 53 | padding: 0.15rem; 54 | font-size: 0.8rem; 55 | border-radius: 15%; 56 | } 57 | 58 | .num_item_content{ 59 | text-align: center; 60 | float: left; 61 | width: 25% !important; 62 | height: calc(100% - 0.8rem) !important; 63 | font-size: 0.8rem !important; 64 | margin: 0.4rem 0.2rem !important; 65 | padding: 0.2rem !important; 66 | border-radius: 10% !important; 67 | } 68 | 69 | .txt_item_content{ 70 | float: left; 71 | width: calc(65% - 2.4rem) !important; 72 | height: calc(100% - 0.8rem) !important; 73 | font-size: 0.8rem !important; 74 | margin: 0.4rem 0.2rem !important; 75 | padding: 0.2rem !important; 76 | border-radius: 3px !important; 77 | } 78 | 79 | .pic_item_take_pic_div{ 80 | float: left; 81 | height: calc(100% - 0.8rem); 82 | margin: 0.5rem 0; 83 | margin-left: 0.3rem; 84 | border-radius: 3px; 85 | } 86 | 87 | .pic_item_take_pic_img{ 88 | width: 1.2rem; 89 | margin-left: 0.2rem; 90 | margin-top: 0.2rem; 91 | } 92 | 93 | .pic_item_take_pic_txt{ 94 | font-size: 0.9rem; 95 | color: white; 96 | float: right; 97 | padding: 0.2rem; 98 | } 99 | 100 | .pic_item_select_pic_btn{ 101 | float: left; 102 | height: calc(100% - 0.8rem); 103 | width: 5.25rem; 104 | margin: 0.5rem 0; 105 | margin-left: 0.3rem; 106 | padding: 0.2rem 0.3rem; 107 | font-size: 0.9rem; 108 | color: white; 109 | border-radius: 3px; 110 | } 111 | 112 | .pic_item_photo_div{ 113 | clear: both; 114 | margin-left: 35%; 115 | } 116 | 117 | .pic_item_photo_img{ 118 | width: 2.5rem; 119 | height: 2.5rem; 120 | background: lightgray; 121 | float: left; 122 | margin: 2px; 123 | } 124 | 125 | .select_item_div{ 126 | float: left; 127 | width: calc(65% - 2rem); 128 | height: 100%; 129 | margin: 0.5rem 0; 130 | } 131 | 132 | .select_item_radio_btn{ 133 | height: 1rem; 134 | width: 1rem; 135 | } 136 | 137 | .select_item_radio_lable{ 138 | font-size: 1rem; 139 | } 140 | 141 | .line{ 142 | clear: both; 143 | height: 1px; 144 | background-color: lightgrey; 145 | } 146 | -------------------------------------------------------------------------------- /web/data/list.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "data": [{ 4 | "e_id": "0_0", 5 | "e_index": 0, 6 | "e_name": "小米电视A4", 7 | "e_state": "0", 8 | "e_remark": "", 9 | "subs": [{ 10 | "i_id": 1, 11 | "e_id": "0_0", 12 | "i_index": 1, 13 | "i_name": "机身温度", 14 | "i_type": 1, 15 | "i_value": "", 16 | "i_status": "", 17 | "i_reference": "-10~60", 18 | "i_content": "", 19 | "i_content_time": "", 20 | "i_remark": "", 21 | "i_default": "", 22 | "i_increment": "0.5", 23 | "i_unit": "C" 24 | }, { 25 | "i_id": 2, 26 | "e_id": "0_0", 27 | "i_index": 2, 28 | "i_name": "开关状态", 29 | "i_type": 2, 30 | "i_value": "开机/关机/待机", 31 | "i_status": "", 32 | "i_reference": "", 33 | "i_content": "", 34 | "i_content_time": "", 35 | "i_remark": "", 36 | "i_default": "", 37 | "i_increment": "", 38 | "i_unit": "" 39 | }, { 40 | "i_id": 3, 41 | "e_id": "0_0", 42 | "i_index": 3, 43 | "i_name": "播放内容", 44 | "i_type": 3, 45 | "i_value": "", 46 | "i_status": "", 47 | "i_reference": "", 48 | "i_content": "海贼王万国篇-路飞VS卡二", 49 | "i_content_time": "", 50 | "i_remark": "", 51 | "i_default": "", 52 | "i_increment": "", 53 | "i_unit": "" 54 | }, { 55 | "i_id": 4, 56 | "e_id": "0_0", 57 | "i_index": 4, 58 | "i_name": "机身状况", 59 | "i_type": 4, 60 | "i_value": "", 61 | "i_status": "", 62 | "i_reference": "", 63 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 64 | "i_content_time": "", 65 | "i_remark": "", 66 | "i_default": "", 67 | "i_increment": "", 68 | "i_unit": "" 69 | }] 70 | }, { 71 | "e_id": "0_0", 72 | "e_index": 0, 73 | "e_name": "小米电视A4", 74 | "e_state": "0", 75 | "e_remark": "remark", 76 | "subs": [{ 77 | "i_id": 1, 78 | "e_id": "0_0", 79 | "i_index": 1, 80 | "i_name": "机身温度", 81 | "i_type": 1, 82 | "i_value": "", 83 | "i_status": "", 84 | "i_reference": "-10~60", 85 | "i_content": "", 86 | "i_content_time": "", 87 | "i_remark": "", 88 | "i_default": "", 89 | "i_increment": "0.5", 90 | "i_unit": "C" 91 | }, { 92 | "i_id": 2, 93 | "e_id": "0_0", 94 | "i_index": 2, 95 | "i_name": "开关状态", 96 | "i_type": 2, 97 | "i_value": "开机/关机/待机", 98 | "i_status": "", 99 | "i_reference": "", 100 | "i_content": "", 101 | "i_content_time": "", 102 | "i_remark": "", 103 | "i_default": "", 104 | "i_increment": "", 105 | "i_unit": "" 106 | }, { 107 | "i_id": 3, 108 | "e_id": "0_0", 109 | "i_index": 3, 110 | "i_name": "播放内容", 111 | "i_type": 3, 112 | "i_value": "", 113 | "i_status": "", 114 | "i_reference": "", 115 | "i_content": "海贼王万国篇-路飞VS卡二", 116 | "i_content_time": "", 117 | "i_remark": "", 118 | "i_default": "", 119 | "i_increment": "", 120 | "i_unit": "" 121 | }, { 122 | "i_id": 4, 123 | "e_id": "0_0", 124 | "i_index": 4, 125 | "i_name": "机身状况", 126 | "i_type": 4, 127 | "i_value": "", 128 | "i_status": "", 129 | "i_reference": "", 130 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 131 | "i_content_time": "", 132 | "i_remark": "", 133 | "i_default": "", 134 | "i_increment": "", 135 | "i_unit": "" 136 | }] 137 | }, { 138 | "e_id": "0_0", 139 | "e_index": 0, 140 | "e_name": "小米电视A4", 141 | "e_state": "0", 142 | "e_remark": "remark", 143 | "subs": [{ 144 | "i_id": 1, 145 | "e_id": "0_0", 146 | "i_index": 1, 147 | "i_name": "机身温度", 148 | "i_type": 1, 149 | "i_value": "", 150 | "i_status": "", 151 | "i_reference": "-10~60", 152 | "i_content": "", 153 | "i_content_time": "", 154 | "i_remark": "", 155 | "i_default": "", 156 | "i_increment": "0.5", 157 | "i_unit": "C" 158 | }, { 159 | "i_id": 2, 160 | "e_id": "0_0", 161 | "i_index": 2, 162 | "i_name": "开关状态", 163 | "i_type": 2, 164 | "i_value": "开机/关机/待机", 165 | "i_status": "", 166 | "i_reference": "", 167 | "i_content": "", 168 | "i_content_time": "", 169 | "i_remark": "", 170 | "i_default": "", 171 | "i_increment": "", 172 | "i_unit": "" 173 | }, { 174 | "i_id": 3, 175 | "e_id": "0_0", 176 | "i_index": 3, 177 | "i_name": "播放内容", 178 | "i_type": 3, 179 | "i_value": "", 180 | "i_status": "", 181 | "i_reference": "", 182 | "i_content": "海贼王万国篇-路飞VS卡二", 183 | "i_content_time": "", 184 | "i_remark": "", 185 | "i_default": "", 186 | "i_increment": "", 187 | "i_unit": "" 188 | }, { 189 | "i_id": 4, 190 | "e_id": "0_0", 191 | "i_index": 4, 192 | "i_name": "机身状况", 193 | "i_type": 4, 194 | "i_value": "", 195 | "i_status": "", 196 | "i_reference": "", 197 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 198 | "i_content_time": "", 199 | "i_remark": "", 200 | "i_default": "", 201 | "i_increment": "", 202 | "i_unit": "" 203 | }] 204 | }, { 205 | "e_id": "0_0", 206 | "e_index": 0, 207 | "e_name": "小米电视A4", 208 | "e_state": "0", 209 | "e_remark": "remark", 210 | "subs": [{ 211 | "i_id": 1, 212 | "e_id": "0_0", 213 | "i_index": 1, 214 | "i_name": "机身温度", 215 | "i_type": 1, 216 | "i_value": "", 217 | "i_status": "", 218 | "i_reference": "-10~60", 219 | "i_content": "", 220 | "i_content_time": "", 221 | "i_remark": "", 222 | "i_default": "", 223 | "i_increment": "0.5", 224 | "i_unit": "C" 225 | }, { 226 | "i_id": 2, 227 | "e_id": "0_0", 228 | "i_index": 2, 229 | "i_name": "开关状态", 230 | "i_type": 2, 231 | "i_value": "开机/关机/待机", 232 | "i_status": "", 233 | "i_reference": "", 234 | "i_content": "", 235 | "i_content_time": "", 236 | "i_remark": "", 237 | "i_default": "", 238 | "i_increment": "", 239 | "i_unit": "" 240 | }, { 241 | "i_id": 3, 242 | "e_id": "0_0", 243 | "i_index": 3, 244 | "i_name": "播放内容", 245 | "i_type": 3, 246 | "i_value": "", 247 | "i_status": "", 248 | "i_reference": "", 249 | "i_content": "海贼王万国篇-路飞VS卡二", 250 | "i_content_time": "", 251 | "i_remark": "", 252 | "i_default": "", 253 | "i_increment": "", 254 | "i_unit": "" 255 | }, { 256 | "i_id": 4, 257 | "e_id": "0_0", 258 | "i_index": 4, 259 | "i_name": "机身状况", 260 | "i_type": 4, 261 | "i_value": "", 262 | "i_status": "", 263 | "i_reference": "", 264 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 265 | "i_content_time": "", 266 | "i_remark": "", 267 | "i_default": "", 268 | "i_increment": "", 269 | "i_unit": "" 270 | }] 271 | }, { 272 | "e_id": "0_0", 273 | "e_index": 0, 274 | "e_name": "小米电视A4", 275 | "e_state": "0", 276 | "e_remark": "remark", 277 | "subs": [{ 278 | "i_id": 1, 279 | "e_id": "0_0", 280 | "i_index": 1, 281 | "i_name": "机身温度", 282 | "i_type": 1, 283 | "i_value": "", 284 | "i_status": "", 285 | "i_reference": "-10~60", 286 | "i_content": "", 287 | "i_content_time": "", 288 | "i_remark": "", 289 | "i_default": "", 290 | "i_increment": "0.5", 291 | "i_unit": "C" 292 | }, { 293 | "i_id": 2, 294 | "e_id": "0_0", 295 | "i_index": 2, 296 | "i_name": "开关状态", 297 | "i_type": 2, 298 | "i_value": "开机/关机/待机", 299 | "i_status": "", 300 | "i_reference": "", 301 | "i_content": "", 302 | "i_content_time": "", 303 | "i_remark": "", 304 | "i_default": "", 305 | "i_increment": "", 306 | "i_unit": "" 307 | }, { 308 | "i_id": 3, 309 | "e_id": "0_0", 310 | "i_index": 3, 311 | "i_name": "播放内容", 312 | "i_type": 3, 313 | "i_value": "", 314 | "i_status": "", 315 | "i_reference": "", 316 | "i_content": "海贼王万国篇-路飞VS卡二", 317 | "i_content_time": "", 318 | "i_remark": "", 319 | "i_default": "", 320 | "i_increment": "", 321 | "i_unit": "" 322 | }, { 323 | "i_id": 4, 324 | "e_id": "0_0", 325 | "i_index": 4, 326 | "i_name": "机身状况", 327 | "i_type": 4, 328 | "i_value": "", 329 | "i_status": "", 330 | "i_reference": "", 331 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 332 | "i_content_time": "", 333 | "i_remark": "", 334 | "i_default": "", 335 | "i_increment": "", 336 | "i_unit": "" 337 | }] 338 | }, { 339 | "e_id": "0_0", 340 | "e_index": 0, 341 | "e_name": "小米电视A4", 342 | "e_state": "0", 343 | "e_remark": "remark", 344 | "subs": [{ 345 | "i_id": 1, 346 | "e_id": "0_0", 347 | "i_index": 1, 348 | "i_name": "机身温度", 349 | "i_type": 1, 350 | "i_value": "", 351 | "i_status": "", 352 | "i_reference": "-10~60", 353 | "i_content": "", 354 | "i_content_time": "", 355 | "i_remark": "", 356 | "i_default": "", 357 | "i_increment": "0.5", 358 | "i_unit": "C" 359 | }, { 360 | "i_id": 2, 361 | "e_id": "0_0", 362 | "i_index": 2, 363 | "i_name": "开关状态", 364 | "i_type": 2, 365 | "i_value": "开机/关机/待机", 366 | "i_status": "", 367 | "i_reference": "", 368 | "i_content": "", 369 | "i_content_time": "", 370 | "i_remark": "", 371 | "i_default": "", 372 | "i_increment": "", 373 | "i_unit": "" 374 | }, { 375 | "i_id": 3, 376 | "e_id": "0_0", 377 | "i_index": 3, 378 | "i_name": "播放内容", 379 | "i_type": 3, 380 | "i_value": "", 381 | "i_status": "", 382 | "i_reference": "", 383 | "i_content": "海贼王万国篇-路飞VS卡二", 384 | "i_content_time": "", 385 | "i_remark": "", 386 | "i_default": "", 387 | "i_increment": "", 388 | "i_unit": "" 389 | }, { 390 | "i_id": 4, 391 | "e_id": "0_0", 392 | "i_index": 4, 393 | "i_name": "机身状况", 394 | "i_type": 4, 395 | "i_value": "", 396 | "i_status": "", 397 | "i_reference": "", 398 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 399 | "i_content_time": "", 400 | "i_remark": "", 401 | "i_default": "", 402 | "i_increment": "", 403 | "i_unit": "" 404 | }] 405 | }, { 406 | "e_id": "0_0", 407 | "e_index": 0, 408 | "e_name": "小米电视A4", 409 | "e_state": "0", 410 | "e_remark": "remark", 411 | "subs": [{ 412 | "i_id": 1, 413 | "e_id": "0_0", 414 | "i_index": 1, 415 | "i_name": "机身温度", 416 | "i_type": 1, 417 | "i_value": "", 418 | "i_status": "", 419 | "i_reference": "-10~60", 420 | "i_content": "", 421 | "i_content_time": "", 422 | "i_remark": "", 423 | "i_default": "", 424 | "i_increment": "0.5", 425 | "i_unit": "C" 426 | }, { 427 | "i_id": 2, 428 | "e_id": "0_0", 429 | "i_index": 2, 430 | "i_name": "开关状态", 431 | "i_type": 2, 432 | "i_value": "开机/关机/待机", 433 | "i_status": "", 434 | "i_reference": "", 435 | "i_content": "", 436 | "i_content_time": "", 437 | "i_remark": "", 438 | "i_default": "", 439 | "i_increment": "", 440 | "i_unit": "" 441 | }, { 442 | "i_id": 3, 443 | "e_id": "0_0", 444 | "i_index": 3, 445 | "i_name": "播放内容", 446 | "i_type": 3, 447 | "i_value": "", 448 | "i_status": "", 449 | "i_reference": "", 450 | "i_content": "海贼王万国篇-路飞VS卡二", 451 | "i_content_time": "", 452 | "i_remark": "", 453 | "i_default": "", 454 | "i_increment": "", 455 | "i_unit": "" 456 | }, { 457 | "i_id": 4, 458 | "e_id": "0_0", 459 | "i_index": 4, 460 | "i_name": "机身状况", 461 | "i_type": 4, 462 | "i_value": "", 463 | "i_status": "", 464 | "i_reference": "", 465 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 466 | "i_content_time": "", 467 | "i_remark": "", 468 | "i_default": "", 469 | "i_increment": "", 470 | "i_unit": "" 471 | }] 472 | }, { 473 | "e_id": "0_0", 474 | "e_index": 0, 475 | "e_name": "小米电视A4", 476 | "e_state": "0", 477 | "e_remark": "remark", 478 | "subs": [{ 479 | "i_id": 1, 480 | "e_id": "0_0", 481 | "i_index": 1, 482 | "i_name": "机身温度", 483 | "i_type": 1, 484 | "i_value": "", 485 | "i_status": "", 486 | "i_reference": "-10~60", 487 | "i_content": "", 488 | "i_content_time": "", 489 | "i_remark": "", 490 | "i_default": "", 491 | "i_increment": "0.5", 492 | "i_unit": "C" 493 | }, { 494 | "i_id": 2, 495 | "e_id": "0_0", 496 | "i_index": 2, 497 | "i_name": "开关状态", 498 | "i_type": 2, 499 | "i_value": "开机/关机/待机", 500 | "i_status": "", 501 | "i_reference": "", 502 | "i_content": "", 503 | "i_content_time": "", 504 | "i_remark": "", 505 | "i_default": "", 506 | "i_increment": "", 507 | "i_unit": "" 508 | }, { 509 | "i_id": 3, 510 | "e_id": "0_0", 511 | "i_index": 3, 512 | "i_name": "播放内容", 513 | "i_type": 3, 514 | "i_value": "", 515 | "i_status": "", 516 | "i_reference": "", 517 | "i_content": "海贼王万国篇-路飞VS卡二", 518 | "i_content_time": "", 519 | "i_remark": "", 520 | "i_default": "", 521 | "i_increment": "", 522 | "i_unit": "" 523 | }, { 524 | "i_id": 4, 525 | "e_id": "0_0", 526 | "i_index": 4, 527 | "i_name": "机身状况", 528 | "i_type": 4, 529 | "i_value": "", 530 | "i_status": "", 531 | "i_reference": "", 532 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 533 | "i_content_time": "", 534 | "i_remark": "", 535 | "i_default": "", 536 | "i_increment": "", 537 | "i_unit": "" 538 | }] 539 | }, { 540 | "e_id": "0_0", 541 | "e_index": 0, 542 | "e_name": "小米电视A4", 543 | "e_state": "0", 544 | "e_remark": "remark", 545 | "subs": [{ 546 | "i_id": 1, 547 | "e_id": "0_0", 548 | "i_index": 1, 549 | "i_name": "机身温度", 550 | "i_type": 1, 551 | "i_value": "", 552 | "i_status": "", 553 | "i_reference": "-10~60", 554 | "i_content": "", 555 | "i_content_time": "", 556 | "i_remark": "", 557 | "i_default": "", 558 | "i_increment": "0.5", 559 | "i_unit": "C" 560 | }, { 561 | "i_id": 2, 562 | "e_id": "0_0", 563 | "i_index": 2, 564 | "i_name": "开关状态", 565 | "i_type": 2, 566 | "i_value": "开机/关机/待机", 567 | "i_status": "", 568 | "i_reference": "", 569 | "i_content": "", 570 | "i_content_time": "", 571 | "i_remark": "", 572 | "i_default": "", 573 | "i_increment": "", 574 | "i_unit": "" 575 | }, { 576 | "i_id": 3, 577 | "e_id": "0_0", 578 | "i_index": 3, 579 | "i_name": "播放内容", 580 | "i_type": 3, 581 | "i_value": "", 582 | "i_status": "", 583 | "i_reference": "", 584 | "i_content": "海贼王万国篇-路飞VS卡二", 585 | "i_content_time": "", 586 | "i_remark": "", 587 | "i_default": "", 588 | "i_increment": "", 589 | "i_unit": "" 590 | }, { 591 | "i_id": 4, 592 | "e_id": "0_0", 593 | "i_index": 4, 594 | "i_name": "机身状况", 595 | "i_type": 4, 596 | "i_value": "", 597 | "i_status": "", 598 | "i_reference": "", 599 | "i_content": "logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg,logo.jpg", 600 | "i_content_time": "", 601 | "i_remark": "", 602 | "i_default": "", 603 | "i_increment": "", 604 | "i_unit": "" 605 | }] 606 | }] 607 | }, 608 | "error_code": "00", 609 | "error_msg": "Succeed" 610 | } 611 | -------------------------------------------------------------------------------- /web/html/expandable-list.html: -------------------------------------------------------------------------------- 1 |

2 |
3 | 18 |
19 | 20 |
21 |
22 |
23 |
-------------------------------------------------------------------------------- /web/html/list-item-tpl.html: -------------------------------------------------------------------------------- 1 | {# 请不要随便格式化此文件代码} 2 |
    3 | {@each equips as equip,parentIndex} 4 |
  • 5 | 9 |
    10 |
    11 |
    12 |
      13 | {@each equip.subs as item,childIndex} 14 | {@if item.i_type == 1} 15 | {# item类型-数据项} 16 |
    • 17 |
      18 | ${item.i_name} 19 | -${item.i_increment} 20 | 21 | +${item.i_increment} 22 |
      23 |
      24 |
    • 25 | {@else if item.i_type == 2} 26 | {# item类型-选择项} 27 |
    • 28 |
      29 | ${item.i_name} 30 |
      31 | {@each item.i_value.split('/') as radio,index} 32 | 33 | ${radio} 34 | {@/each} 35 |
      36 |
      37 |
      38 |
    • 39 | {@else if item.i_type == 3} 40 | {# item类型-说明项} 41 |
    • 42 |
      43 | ${item.i_name} 44 | 45 |
      46 |
      47 |
    • 48 | {@else if item.i_type == 4} 49 | {# item类型-拍照项} 50 |
    • 51 |
      52 | ${item.i_name} 53 |
      54 | 55 | 拍照 56 |
      57 | 从相册选择 58 |
      59 |
      60 | {@if item.i_content.trim() != ""} 61 | {@each item.i_content.trim().split(',') as pic,index} 62 | 63 | {@/each} 64 | {@/if} 65 |
      66 |
      67 |
    • 68 | {@/if} 69 | {@/each} 70 |
    71 |
    72 |
    73 |
  • 74 | {@/each} 75 |
-------------------------------------------------------------------------------- /web/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/web/images/.DS_Store -------------------------------------------------------------------------------- /web/images/camera_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/web/images/camera_img.png -------------------------------------------------------------------------------- /web/images/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/web/images/img.png -------------------------------------------------------------------------------- /web/images/item_remark_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/web/images/item_remark_img.png -------------------------------------------------------------------------------- /web/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/web/images/logo.jpg -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | fxp 10 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 | 50 |
51 | 52 |
53 | 54 | 55 | 58 |
59 |
60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /web/js/accordion.js: -------------------------------------------------------------------------------- 1 | /*=============================================================================== 2 | ************ Accordion ************ 3 | ===============================================================================*/ 4 | (function () { 5 | var $ = $$, app = myApp; 6 | 7 | app.accordionOpenv1 = function (item) { 8 | item = $(item); 9 | var list = item.parents('.cusv1-accordion-list').eq(0); 10 | var content = item.children('.accordion-item-content'); 11 | if (content.length === 0) content = item.find('.accordion-item-content'); 12 | var expandedItem = list.length > 0 && item.parent().children('.accordion-item-expanded'); 13 | if (expandedItem.length > 0) { 14 | // 打开当前item项时,关闭其他item项 15 | // app.accordionClose(expandedItem); 16 | } 17 | content.css('height', content[0].scrollHeight + 'px').transitionEnd(function () { 18 | if (item.hasClass('accordion-item-expanded')) { 19 | content.transition(0); 20 | content.css('height', 'auto'); 21 | var clientLeft = content[0].clientLeft; 22 | content.transition(''); 23 | item.trigger('opened'); 24 | } 25 | /* else { 26 | content.css('height', ''); 27 | item.trigger('closed'); 28 | } */ 29 | }); 30 | item.trigger('open'); 31 | item.addClass('accordion-item-expanded'); 32 | }; 33 | app.accordionClosev1 = function (item) { 34 | item = $(item); 35 | var content = item.children('.accordion-item-content'); 36 | if (content.length === 0) content = item.find('.accordion-item-content'); 37 | item.removeClass('accordion-item-expanded'); 38 | content.transition(0); 39 | content.css('height', content[0].scrollHeight + 'px'); 40 | // Relayout 41 | var clientLeft = content[0].clientLeft; 42 | // Close 43 | content.transition(''); 44 | content.css('height', '').transitionEnd(function () { 45 | /* if (item.hasClass('accordion-item-expanded')) { 46 | content.transition(0); 47 | content.css('height', 'auto'); 48 | var clientLeft = content[0].clientLeft; 49 | content.transition(''); 50 | item.trigger('opened'); 51 | } 52 | else {*/ 53 | content.css('height', ''); 54 | item.trigger('closed'); 55 | // } 56 | }); 57 | item.trigger('close'); 58 | }; 59 | 60 | })(); -------------------------------------------------------------------------------- /web/js/expandable-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by fxp on 2018/2/7. 3 | */ 4 | var $$ = Dom7; 5 | 6 | var myApp = new Framework7(); 7 | 8 | var mainView = myApp.addView('.view-main'); 9 | 10 | var expandableList = function () { 11 | var page, // 页面DOM 12 | templateStr, // 列表模板html 13 | imageDir = "images/"; // 图片路径 14 | 15 | /* 16 | * 获取模板文本 17 | * */ 18 | $$.get("html/list-item-tpl.html", function (data) { 19 | templateStr = data; 20 | }); 21 | 22 | /* 23 | * 加载expandable-list.html 24 | * */ 25 | mainView.router.load( 26 | { 27 | url: 'html/expandable-list.html' 28 | } 29 | ); 30 | 31 | /** 32 | * 页面生命周期监听-pageBeforeInit 33 | */ 34 | $$(document).on('pageBeforeInit', function (e) { 35 | let page = e.detail.page; 36 | if (page.name === 'expandable-list') { 37 | expandableList.beforeInit(page); 38 | } 39 | }); 40 | 41 | /** 42 | * 页面生命周期监听-pageInit 43 | */ 44 | $$(document).on('pageInit', function (e) { 45 | let page = e.detail.page; 46 | if (page.name === 'expandable-list') { 47 | expandableList.init(page); 48 | } 49 | }); 50 | 51 | /** 52 | * 页面生命周期监听-pageBeforeAnimation 53 | */ 54 | $$(document).on('pageBeforeAnimation', function (e) { 55 | let page = e.detail.page; 56 | if (page.name === 'expandable-list') { 57 | expandableList.beforeAnimation(page); 58 | } 59 | }); 60 | 61 | /** 62 | * 页面生命周期监听-pageBeforeRemove 63 | */ 64 | $$(document).on('pageBeforeRemove', function (e) { 65 | let page = e.detail.page; 66 | if (page.name === 'expandable-list') { 67 | expandableList.beforeRemove(page); 68 | } 69 | }); 70 | 71 | /** 72 | * pageBeforeInit回调 73 | * @param {*} p 74 | */ 75 | function beforeInit(p) { 76 | page = $$(p.container); 77 | 78 | } 79 | 80 | /** 81 | * pageInit回调 82 | * @param {*} p 83 | */ 84 | function init(p) { 85 | 86 | initViews(); 87 | 88 | bindEvent('on'); 89 | } 90 | 91 | /** 92 | * pageBeforeAnimation回调 93 | * @param {*} p 94 | */ 95 | function beforeAnimation(p) { 96 | 97 | } 98 | 99 | /** 100 | * pageBeforeRemove回调 101 | * @param {*} p 102 | */ 103 | function beforeRemove(p) { 104 | 105 | bindEvent('off'); 106 | 107 | destroy(); 108 | } 109 | 110 | /** 111 | * 绑定/卸载事件 112 | * @param {*} method 113 | */ 114 | function bindEvent(method) { 115 | if (method === 'on' || method === 'off') { 116 | page[method]("click",".accordion_outer_equip_name",listStateHandler); 117 | } 118 | } 119 | 120 | function initViews() { 121 | utils.get("data/list.json",function(res){ 122 | var data = JSON.parse(res).data.data; 123 | rendList(data); 124 | },function(error){ 125 | 126 | }); 127 | } 128 | 129 | /** 130 | * 组装、渲染列表 131 | * @param {*二级列表数据} items 132 | */ 133 | function rendList(items) { 134 | var datas, htmlstr = '', accordionList; 135 | datas = { 136 | equips: items, 137 | img_dir: imageDir 138 | }; 139 | try { 140 | htmlstr = juicer(templateStr, datas); 141 | accordionList = page.find("#accordion-list"); 142 | accordionList.html(htmlstr); 143 | } catch (error) { 144 | console.log(error); 145 | } 146 | } 147 | 148 | /* 149 | * 二级列表打开/收缩事件 150 | * */ 151 | function listStateHandler(e) { 152 | let item = $$(this).parents(".cusv1-accordion-item"); 153 | if (item.hasClass("accordion-item-expanded")) { 154 | myApp.accordionClosev1(item); 155 | } else { 156 | myApp.accordionOpenv1(item); 157 | } 158 | } 159 | 160 | function destroy() { 161 | page = null; 162 | 163 | } 164 | 165 | return { 166 | beforeInit: beforeInit, 167 | init: init, 168 | beforeAnimation: beforeAnimation, 169 | beforeRemove: beforeRemove, 170 | } 171 | }(); 172 | 173 | var utils = { 174 | post: function (data, sf, ef, p) { 175 | var url = utils.postUrl(); 176 | $$.ajax({ 177 | url: url, 178 | async: true, 179 | method: 'POST', 180 | contentType: 'text/plain', 181 | crossDomain: true, 182 | data: data, 183 | success: function (e) { 184 | if ("function" == typeof sf) 185 | sf(e, p); 186 | }, 187 | error: function (e) { 188 | console.log(e); 189 | if ("function" == typeof ef) 190 | ef(e, p); 191 | } 192 | }); 193 | }, 194 | get: function (url, sf, ef, p) { 195 | $$.ajax({ 196 | url: url, 197 | async: true, 198 | method: 'GET', 199 | contentType: 'application/x-www-form-urlencoded', 200 | crossDomain: true, 201 | success: function (e) { 202 | if ('function' == typeof sf) 203 | sf(e, p); 204 | }, 205 | error: function (e) { 206 | if ('function' == typeof ef) 207 | ef(e, p); 208 | } 209 | }); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /web/libs/framework7/css/my-app.css: -------------------------------------------------------------------------------- 1 | html * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .page { 6 | background-color: rgb(245, 245, 245) !important; 7 | } 8 | 9 | .page-header { 10 | width: 100%; 11 | height: 46px; 12 | background: #ff7f1f; 13 | } 14 | 15 | .page-body { 16 | width: 100%; 17 | height: calc(100% - 46px); 18 | } 19 | 20 | .page-header-inner { 21 | width: 100%; 22 | height: 100%; 23 | clear: both; 24 | } 25 | 26 | .page-header-inner .left, .page-header-inner .center, .page-header-inner .right { 27 | width: 33.3%; 28 | height: 100%; 29 | float: left; 30 | vertical-align: middle; 31 | line-height: 2.5; 32 | font-size: 1.125rem; 33 | color: white; 34 | } 35 | 36 | .page-header-inner .left { 37 | text-align: left; 38 | padding-left: 1.25rem; 39 | } 40 | 41 | .page-header-inner .center { 42 | text-align: center; 43 | overflow: hidden; 44 | white-space: nowrap; 45 | text-overflow: ellipsis; 46 | } 47 | 48 | .page-header-inner .right { 49 | text-align: right; 50 | padding-right: 1.25rem; 51 | } 52 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-f7-ios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/web/libs/framework7/img/i-f7-ios.png -------------------------------------------------------------------------------- /web/libs/framework7/img/i-f7-material.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fangxiaopeng/multi-expandable-list/97423703d4ecd2cf83c4c15460b7889c5dca0abe/web/libs/framework7/img/i-f7-material.png -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-calendar-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-calendar-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-comment-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-comment-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-email-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-email-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-gender-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-gender-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-name-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-name-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-password-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-password-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-settings-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-settings-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-tel-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-tel-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-toggle-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-toggle-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-url-ios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /web/libs/framework7/img/i-form-url-material.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /web/libs/framework7/js/init-app.js: -------------------------------------------------------------------------------- 1 | // Determine theme depending on device 2 | var isAndroid = Framework7.prototype.device.android === true; 3 | var isIos = Framework7.prototype.device.ios === true; 4 | 5 | // Set Template7 global devices flags 6 | Template7.global = { 7 | android: isAndroid, 8 | ios: isIos 9 | }; 10 | 11 | // Define Dom7 12 | var $$ = Dom7; 13 | 14 | // Add CSS Styles 15 | if (isAndroid) { 16 | $$('head').append( 17 | '' + 18 | '' 19 | ); 20 | } else { 21 | $$('head').append( 22 | '' + 23 | '' 24 | ); 25 | } 26 | 27 | // Change Through navbar layout to Fixed 28 | if (!isAndroid) { 29 | // Change class 30 | $$('.view.navbar-through').removeClass('navbar-through').addClass('navbar-fixed'); 31 | // And move Navbar into Page 32 | $$('.view .navbar').prependTo('.view .page'); 33 | } 34 | -------------------------------------------------------------------------------- /web/libs/juicer-min.js: -------------------------------------------------------------------------------- 1 | !function(){var e=function(){var t=[].slice.call(arguments);return t.push(e.options),t[0].match(/^\s*#([\w:\-\.]+)\s*$/gim)&&t[0].replace(/^\s*#([\w:\-\.]+)\s*$/gim,function(e,n){var o=document,i=o&&o.getElementById(n);t[0]=i?i.value||i.innerHTML:e}),e.documentHTML&&(e.compile.call(e,e.documentHTML),e.documentHTML=""),1==arguments.length?e.compile.apply(e,t):arguments.length>=2?e.to_html.apply(e,t):void 0},t={escapehash:{"<":"<",">":">","&":"&",'"':""","'":"'","/":"/"},escapereplace:function(e){return t.escapehash[e]},escaping:function(e){return"string"!=typeof e?e:e.replace(/[&<>"']/gim,this.escapereplace)},detection:function(e){return"undefined"==typeof e?"":e}},n=function(e){if("undefined"!=typeof console){if(console.warn)return void console.warn(e);if(console.log)return void console.log(e)}throw e},o=function(e,t){if(e=e!==Object(e)?{}:e,e.__proto__)return e.__proto__=t,e;var n=function(){},o=Object.create?Object.create(t):new(n.prototype=t,n);for(var i in e)e.hasOwnProperty(i)&&(o[i]=e[i]);return o},i=function(e){var t,n,o,i=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,r=/,/,s=/^\s*(_?)(\S+?)\1\s*$/,a=/^function[^{]+{([\s\S]*)}/m,c=[];"function"==typeof e?e.length&&(t=e.toString()):"string"==typeof e&&(t=e),t=t.trim(),o=t.match(i),n=t.match(a)[1].trim();for(var p=0;p1&&(e=i.shift(),o=i.shift().split(","),r="_method."+o.shift()+".call(this, "+[e].concat(o)+")"),"<%= "+(t?"_method.__escapehtml.escaping":"")+"("+(n&&n.detection===!1?"":"_method.__escapehtml.detection")+"("+r+")) %>"},this.__removeShell=function(t,o){var r=0;return t=t.replace(e.settings.helperRegister,function(t,n,o){var r=i(o),s=r[0],a=r[1],c=new Function(s.join(","),a);return e.register(n,c),t}).replace(e.settings.forstart,function(e,t,n,o){var n=n||"value",o=o&&o.substr(1),i="i"+r++;return"<% ~function() {for(var "+i+" in "+t+") {if("+t+".hasOwnProperty("+i+")) {var "+n+"="+t+"["+i+"];"+(o?"var "+o+"="+i+";":"")+" %>"}).replace(e.settings.forend,"<% }}}(); %>").replace(e.settings.ifstart,function(e,t){return"<% if("+t+") { %>"}).replace(e.settings.ifend,"<% } %>").replace(e.settings.elsestart,function(){return"<% } else { %>"}).replace(e.settings.elseifstart,function(e,t){return"<% } else if("+t+") { %>"}).replace(e.settings.noneencode,function(e,t){return n.__interpolate(t,!1,o)}).replace(e.settings.interpolate,function(e,t){return n.__interpolate(t,!0,o)}).replace(e.settings.inlinecomment,"").replace(e.settings.rangestart,function(e,t,n,o){var i="j"+r++;return"<% ~function() {for(var "+i+"="+n+";"+i+"<"+o+";"+i+"++) {{var "+t+"="+i+"; %>"}).replace(e.settings.include,function(e,t,n){return t.match(/^file\:\/\//gim)?e:"<%= _method.__juicer("+t+", "+n+"); %>"}),o&&o.errorhandling===!1||(t="<% try { %>"+t,t+='<% } catch(e) {_method.__throw("Juicer Render Exception: "+e.message);} %>'),t},this.__toNative=function(e,t){return this.__convert(e,!t||t.strip)},this.__lexicalAnalyze=function(t){var n=[],o=[],i="",r=["if","each","_","_method","console","break","case","catch","continue","debugger","default","delete","do","finally","for","function","in","instanceof","new","return","switch","this","throw","try","typeof","var","void","while","with","null","typeof","class","enum","export","extends","import","super","implements","interface","let","package","private","protected","public","static","yield","const","arguments","true","false","undefined","NaN"],s=function(e,t){if(Array.prototype.indexOf&&e.indexOf===Array.prototype.indexOf)return e.indexOf(t);for(var n=0;n=,\(\)\[\]]\s*([A-Za-z_0-9]+)/gim,a);for(var c=0;c"},this.__convert=function(e,t){var n=[].join("");return n+="'use strict';",n+="var _=_||{};",n+="var _out='';_out+='",n+=t!==!1?e.replace(/\\/g,"\\\\").replace(/[\r\t\n]/g," ").replace(/'(?=[^%]*%>)/g," ").split("'").join("\\'").split(" ").join("'").replace(/<%=(.+?)%>/g,"';_out+=$1;_out+='").split("<%").join("';").split("%>").join("_out+='")+"';return _out;":e.replace(/\\/g,"\\\\").replace(/[\r]/g,"\\r").replace(/[\t]/g,"\\t").replace(/[\n]/g,"\\n").replace(/'(?=[^%]*%>)/g," ").split("'").join("\\'").split(" ").join("'").replace(/<%=(.+?)%>/g,"';_out+=$1;_out+='").split("<%").join("';").split("%>").join("_out+='")+"';return _out.replace(/[\\r\\n]\\s+[\\r\\n]/g, '\\r\\n');"},this.parse=function(e,t){var i=this;return t&&t.loose===!1||(e=this.__lexicalAnalyze(e)+e),e=this.__removeShell(e,t),e=this.__toNative(e,t),this._render=new Function("_, _method",e),this.render=function(e,t){return t&&t===n.options._method||(t=o(t,n.options._method)),i._render.call(this,e,t)},this}},e.compile=function(e,t){t&&t===this.options||(t=o(t,this.options));var i=this,r={get:function(e){return t.cachestore?t.cachestore.get(e):i.__cache[e]},set:function(e,n){return t.cachestore?t.cachestore.set(e,n):i.__cache[e]=n}};try{var s=r.get(e)?r.get(e):new this.template(this.options).parse(e,t);return t&&t.cache===!1||r.set(e,s),s}catch(a){return n("Juicer Compile Exception: "+a.message),{render:function(){}}}},e.to_html=function(e,t,n){return n&&n===this.options||(n=o(n,this.options)),this.compile(e,n).render(t,n._method)},"undefined"!=typeof global&&"undefined"==typeof window&&e.set("cache",!1),"undefined"!=typeof document&&document.body&&(e.documentHTML=document.body.innerHTML),"undefined"!=typeof module&&module.exports?module.exports=e:this.juicer=e}(); --------------------------------------------------------------------------------