├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── mydemo │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── mydemo │ │ │ ├── MainActivity.java │ │ │ ├── MyApplication.java │ │ │ ├── activity │ │ │ └── OrgContactActivity.java │ │ │ ├── adapter │ │ │ ├── MainItemAdapter.java │ │ │ └── OrgContactAdapter.java │ │ │ ├── entity │ │ │ ├── AllVo.java │ │ │ ├── EmpUserVo.java │ │ │ ├── OrgVo.java │ │ │ └── ResultVo.java │ │ │ ├── utils │ │ │ └── LogUtils.java │ │ │ └── view │ │ │ └── RecyclerViewItemDecoration.java │ └── res │ │ ├── drawable-xhdpi │ │ └── common_arrow.png │ │ ├── drawable │ │ └── bg_item_selector.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_org_contact.xml │ │ ├── list_item_all.xml │ │ ├── list_item_emp.xml │ │ ├── list_item_main.xml │ │ └── list_item_org.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── mydemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 高仿钉钉组织架构选人、选部门!可单选、全选! 2 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.1" 6 | defaultConfig { 7 | applicationId "com.example.mydemo" 8 | minSdkVersion 14 9 | targetSdkVersion 25 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:25.3.1' 28 | compile 'com.android.support:recyclerview-v7:25.3.1' 29 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 30 | testCompile 'junit:junit:4.12' 31 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.16' 32 | compile 'com.google.code.gson:gson:2.7' 33 | compile 'com.lzy.net:okgo:2.1.4' 34 | } 35 | -------------------------------------------------------------------------------- /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 D:\soft\AndroidStudio\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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/mydemo/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo; 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("com.example.mydemo", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Color; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.os.Bundle; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | 11 | import com.chad.library.adapter.base.BaseQuickAdapter; 12 | import com.example.mydemo.activity.OrgContactActivity; 13 | import com.example.mydemo.adapter.MainItemAdapter; 14 | import com.example.mydemo.adapter.OrgContactAdapter; 15 | import com.example.mydemo.view.RecyclerViewItemDecoration; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class MainActivity extends AppCompatActivity implements BaseQuickAdapter.OnItemClickListener { 21 | 22 | private RecyclerView recyclerView; 23 | private LinearLayoutManager linearLayoutManager; 24 | private MainItemAdapter adapter; 25 | private List list = new ArrayList<>(); 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | recyclerView = (RecyclerView) findViewById(R.id.recyclerView); 32 | linearLayoutManager = new LinearLayoutManager(this); 33 | recyclerView.setLayoutManager(linearLayoutManager); 34 | recyclerView.addItemDecoration(new RecyclerViewItemDecoration.Builder(this) 35 | //.color(Color.RED) 36 | .color("#eeeeee") 37 | // .dashWidth(8) 38 | // .dashGap(5) 39 | .thickness(1) 40 | //.drawableID(R.drawable.diver) 41 | //.paddingStart(20) 42 | //.paddingEnd(10) 43 | //.firstLineVisible(true) 44 | .lastLineVisible(true) 45 | .create()); 46 | 47 | adapter = new MainItemAdapter(); 48 | recyclerView.setAdapter(adapter); 49 | initData(); 50 | adapter.setOnItemClickListener(this); 51 | } 52 | 53 | private void initData() { 54 | list.add("demo1"); 55 | list.add("demo2"); 56 | list.add("demo3"); 57 | adapter.setNewData(list); 58 | } 59 | 60 | @Override 61 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) { 62 | switch (position){ 63 | case 0: 64 | Intent intent = new Intent(MainActivity.this, OrgContactActivity.class); 65 | startActivity(intent); 66 | break; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo; 2 | 3 | import android.app.Application; 4 | 5 | import com.example.mydemo.utils.LogUtils; 6 | import com.lzy.okgo.OkGo; 7 | import com.lzy.okgo.cache.CacheMode; 8 | 9 | import java.util.logging.Level; 10 | 11 | /** 12 | * Created by jack on 2017/5/21. 13 | */ 14 | 15 | public class MyApplication extends Application { 16 | public static LogUtils.Builder lBuilder; 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | //必须调用初始化 21 | OkGo.init(this); 22 | try { 23 | //以下都不是必须的,根据需要自行选择,一般来说只需要 debug,缓存相关,cookie相关的 就可以了 24 | OkGo.getInstance() 25 | // 打开该调试开关,打印级别INFO,并不是异常,是为了显眼,不需要就不要加入该行 26 | // 最后的true表示是否打印okgo的内部异常,一般打开方便调试错误 27 | .debug("OkGo", Level.INFO, true) 28 | //如果使用默认的 60秒,以下三行也不需要传 29 | .setConnectTimeout(OkGo.DEFAULT_MILLISECONDS) //全局的连接超时时间 30 | .setReadTimeOut(OkGo.DEFAULT_MILLISECONDS) //全局的读取超时时间 31 | .setWriteTimeOut(OkGo.DEFAULT_MILLISECONDS) //全局的写入超时时间 32 | 33 | //可以全局统一设置缓存模式,默认是不使用缓存,可以不传,具体其他模式看 github 介绍 https://github.com/jeasonlzy/ 34 | .setCacheMode(CacheMode.REQUEST_FAILED_READ_CACHE); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | 39 | lBuilder = new LogUtils.Builder(this) 40 | .setLogSwitch(BuildConfig.DEBUG)// 设置log总开关,默认开 41 | .setGlobalTag("CMJ")// 设置log全局标签,默认为空 42 | // 当全局标签不为空时,我们输出的log全部为该tag, 43 | // 为空时,如果传入的tag为空那就显示类名,否则显示tag 44 | .setLog2FileSwitch(false)// 打印log时是否存到文件的开关,默认关 45 | .setBorderSwitch(true)// 输出日志是否带边框开关,默认开 46 | .setLogFilter(LogUtils.E);// log过滤器,和logcat过滤器同理,默认Verbose 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/activity/OrgContactActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.activity; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.Gravity; 11 | import android.view.View; 12 | import android.widget.Button; 13 | import android.widget.CheckBox; 14 | import android.widget.HorizontalScrollView; 15 | import android.widget.ImageView; 16 | import android.widget.LinearLayout; 17 | import android.widget.LinearLayout.LayoutParams; 18 | import android.widget.TextView; 19 | 20 | import com.chad.library.adapter.base.BaseQuickAdapter; 21 | import com.chad.library.adapter.base.BaseViewHolder; 22 | import com.chad.library.adapter.base.entity.MultiItemEntity; 23 | import com.example.mydemo.R; 24 | import com.example.mydemo.adapter.OrgContactAdapter; 25 | import com.example.mydemo.entity.AllVo; 26 | import com.example.mydemo.entity.EmpUserVo; 27 | import com.example.mydemo.entity.OrgVo; 28 | import com.example.mydemo.entity.ResultVo; 29 | import com.example.mydemo.utils.LogUtils; 30 | import com.example.mydemo.view.RecyclerViewItemDecoration; 31 | import com.google.gson.Gson; 32 | import com.lzy.okgo.OkGo; 33 | import com.lzy.okgo.callback.StringCallback; 34 | 35 | import java.util.ArrayList; 36 | import java.util.Iterator; 37 | import java.util.List; 38 | 39 | import okhttp3.Call; 40 | import okhttp3.Response; 41 | 42 | /** 43 | * Created by jack on 2017/5/21. 44 | */ 45 | 46 | public class OrgContactActivity extends AppCompatActivity implements BaseQuickAdapter.OnItemClickListener, OrgContactAdapter.OnSubordinateClickListener { 47 | 48 | private HorizontalScrollView horizontalScrollView; 49 | private LinearLayout ll_shortcut; 50 | private RecyclerView recyclerView; 51 | private LinearLayoutManager linearLayoutManager; 52 | private TextView tv_select; 53 | private Button btn_ok; 54 | private OrgContactAdapter adapter; 55 | private List list = new ArrayList<>(); 56 | private List orgList = new ArrayList<>(); 57 | private List empList = new ArrayList<>(); 58 | private List selectAllList = new ArrayList<>(); 59 | private List selectOrgList = new ArrayList<>(); 60 | private List selectEmpList = new ArrayList<>(); 61 | private AllVo curAllVo; 62 | 63 | @Override 64 | protected void onCreate(@Nullable Bundle savedInstanceState) { 65 | super.onCreate(savedInstanceState); 66 | setContentView(R.layout.activity_org_contact); 67 | horizontalScrollView = (HorizontalScrollView)findViewById(R.id.horizontalScrollView); 68 | ll_shortcut = (LinearLayout) findViewById(R.id.ll_shortcut); 69 | tv_select = (TextView) findViewById(R.id.tv_select); 70 | btn_ok = (Button) findViewById(R.id.btn_ok); 71 | recyclerView = (RecyclerView)findViewById(R.id.recyclerView); 72 | linearLayoutManager = new LinearLayoutManager(this); 73 | recyclerView.setLayoutManager(linearLayoutManager); 74 | recyclerView.addItemDecoration(new RecyclerViewItemDecoration.Builder(this) 75 | .color("#eeeeee") 76 | .thickness(1) 77 | .lastLineVisible(true) 78 | .create()); 79 | adapter = new OrgContactAdapter(list, selectAllList, selectOrgList, selectEmpList); 80 | recyclerView.setAdapter(adapter); 81 | adapter.setOnItemClickListener(this); 82 | adapter.setOnSubordinateClickListener(this); 83 | getOrgContacts(""); 84 | } 85 | 86 | private void addView2HorizontalScrollView(OrgVo orgVo){ 87 | LinearLayout linearLayout = new LinearLayout(this); 88 | LayoutParams ll_layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 89 | linearLayout.setLayoutParams(ll_layoutParams); 90 | int count = ll_shortcut.getChildCount(); 91 | if(count>0) { 92 | LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 93 | ImageView imageView = new ImageView(this); 94 | imageView.setBackgroundResource(R.drawable.common_arrow); 95 | layoutParams.gravity = Gravity.CENTER_VERTICAL; 96 | imageView.setLayoutParams(layoutParams); 97 | linearLayout.addView(imageView); 98 | } 99 | LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 100 | TextView textView = new TextView(this); 101 | textView.setText(orgVo.getName()); 102 | textView.setTextColor(Color.BLACK); 103 | if(count>0) { 104 | LinearLayout linearLayout1 = (LinearLayout) ll_shortcut.getChildAt(count-1); 105 | TextView textView1 = (TextView) linearLayout1.getChildAt(linearLayout1.getChildCount()-1); 106 | textView1.setTextColor(Color.BLUE); 107 | } 108 | textView.setLayoutParams(layoutParams); 109 | textView.setTag(orgVo); 110 | textView.setOnClickListener(new View.OnClickListener() { 111 | @Override 112 | public void onClick(View v) { 113 | clickTextView((TextView) v); 114 | } 115 | }); 116 | linearLayout.addView(textView); 117 | ll_shortcut.addView(linearLayout); 118 | new Handler().post(new Runnable() { 119 | @Override 120 | public void run() { 121 | horizontalScrollView.fullScroll(View.FOCUS_RIGHT); 122 | } 123 | }); 124 | } 125 | 126 | private void clickTextView(TextView tv){ 127 | OrgVo orgVo = (OrgVo) tv.getTag(); 128 | tv.setTextColor(Color.BLACK); 129 | int index = ll_shortcut.indexOfChild((View) tv.getParent()); 130 | int count = ll_shortcut.getChildCount(); 131 | ll_shortcut.removeViews(index+1,count-(index+1)); 132 | getOrgContacts(orgVo.getId()); 133 | } 134 | 135 | private void getOrgContacts(String code){ 136 | list.clear(); 137 | orgList.clear(); 138 | empList.clear(); 139 | String url = "http://101.201.108.172:8280/masCustomer/service/UserInfoService/getEmployeeOrg"; 140 | OkGo.post(url) 141 | .tag(this) 142 | .params("servId", "") 143 | .params("orgCode", code) 144 | .params("servId", "") 145 | .params("loginId", "1213") 146 | .params("token", "311f4f508d776b115827e76bd11ae724") 147 | .execute(new StringCallback() { 148 | @Override 149 | public void onError(Call call, Response response, Exception e) { 150 | LogUtils.e(e.toString()); 151 | } 152 | 153 | @Override 154 | public void onSuccess(String s, Call call, Response response) { 155 | Gson gson = new Gson(); 156 | ResultVo resultVo = gson.fromJson(s, ResultVo.class); 157 | String json = gson.toJson(resultVo.getMsg()); 158 | OrgVo orgVo = gson.fromJson(json, OrgVo.class); 159 | if(orgVo!=null) { 160 | if(ll_shortcut.getChildCount()==0) { 161 | addView2HorizontalScrollView(orgVo); 162 | } 163 | handleData(orgVo); 164 | } 165 | } 166 | }); 167 | } 168 | 169 | private void handleData(OrgVo orgVo) { 170 | curAllVo = new AllVo(); 171 | curAllVo.setOrgId(orgVo.getId()); 172 | list.add(curAllVo); 173 | orgList.addAll(orgVo.getOrgVOs()); 174 | list.addAll(orgList); 175 | empList.addAll(orgVo.getUsers()); 176 | list.addAll(empList); 177 | adapter.setNewData(list); 178 | } 179 | 180 | @Override 181 | public void onItemClick(BaseQuickAdapter adapter, View view, int position) { 182 | MultiItemEntity entity = (MultiItemEntity) adapter.getData().get(position); 183 | CheckBox checkbox = (CheckBox) view.findViewById(R.id.checkbox); 184 | checkbox.setChecked(!checkbox.isChecked()); 185 | switch (entity.getItemType()){ 186 | case OrgContactAdapter.ALL: 187 | AllVo allVo = (AllVo) entity; 188 | if(checkbox.isChecked()){ 189 | selectAllList.add(allVo); 190 | 191 | for(OrgVo orgVo : orgList){ 192 | if(!selectOrgList.contains(orgVo)){ 193 | selectOrgList.add(orgVo); 194 | selectAllUserByOrg(orgVo); 195 | } 196 | } 197 | 198 | for(EmpUserVo empUserVo : empList){ 199 | if(!selectEmpList.contains(empUserVo)){ 200 | selectEmpList.add(empUserVo); 201 | } 202 | } 203 | }else{ 204 | selectAllList.remove(allVo); 205 | 206 | for(OrgVo orgVo : orgList){ 207 | if(selectOrgList.contains(orgVo)){ 208 | selectOrgList.remove(orgVo); 209 | unSelectAllUserByOrg(orgVo); 210 | } 211 | } 212 | 213 | for(EmpUserVo empUserVo : empList){ 214 | if(selectEmpList.contains(empUserVo)){ 215 | selectEmpList.remove(empUserVo); 216 | } 217 | } 218 | } 219 | refreshSelectText(); 220 | break; 221 | 222 | case OrgContactAdapter.ORG: 223 | OrgVo orgVo = (OrgVo) entity; 224 | if(checkbox.isChecked()){ 225 | if(!selectOrgList.contains(orgVo)) { 226 | selectOrgList.add(orgVo); 227 | selectAllUserByOrg(orgVo); 228 | } 229 | }else{ 230 | if(selectOrgList.contains(orgVo)) { 231 | selectOrgList.remove(orgVo); 232 | unSelectAllUserByOrg(orgVo); 233 | } 234 | if(selectAllList.contains(curAllVo)) { 235 | selectAllList.remove(curAllVo); 236 | } 237 | } 238 | refreshSelectText(); 239 | break; 240 | 241 | case OrgContactAdapter.EMP: 242 | EmpUserVo empUserVo = (EmpUserVo) entity; 243 | if(checkbox.isChecked()){ 244 | if(!selectEmpList.contains(empUserVo)) { 245 | selectEmpList.add(empUserVo); 246 | } 247 | }else{ 248 | if(selectEmpList.contains(empUserVo)) { 249 | selectEmpList.remove(empUserVo); 250 | } 251 | if(selectAllList.contains(curAllVo)) { 252 | selectAllList.remove(curAllVo); 253 | } 254 | } 255 | refreshSelectText(); 256 | break; 257 | } 258 | } 259 | 260 | private void refreshSelectText() { 261 | String str = "已选择" + selectOrgList.size()+ "个部门" + selectEmpList.size()+ "个人"; 262 | tv_select.setText(str); 263 | adapter.notifyDataSetChanged(); 264 | } 265 | 266 | @Override 267 | public void onSubordinateClick(BaseViewHolder helper, View v, int position) { 268 | OrgVo orgVo = (OrgVo) adapter.getData().get(position); 269 | addView2HorizontalScrollView(orgVo); 270 | getOrgContacts(orgVo.getId()); 271 | } 272 | 273 | private void selectAllUserByOrg(OrgVo orgVo){ 274 | ArrayList orgList = orgVo.getOrgVOs(); 275 | ArrayList userList = orgVo.getUsers(); 276 | for(EmpUserVo empUserVo : userList){ 277 | if(!selectEmpList.contains(empUserVo)) { 278 | selectEmpList.add(empUserVo); 279 | } 280 | } 281 | for(OrgVo vo : orgList){ 282 | selectAllUserByOrg(vo); 283 | } 284 | } 285 | 286 | private void unSelectAllUserByOrg(OrgVo orgVo){ 287 | ArrayList orgList = orgVo.getOrgVOs(); 288 | ArrayList userList = orgVo.getUsers(); 289 | for(EmpUserVo empUserVo : userList){ 290 | if(selectEmpList.contains(empUserVo)) { 291 | selectEmpList.remove(empUserVo); 292 | } 293 | } 294 | for(OrgVo vo : orgList){ 295 | unSelectAllUserByOrg(vo); 296 | if(selectOrgList.contains(vo)) { 297 | selectOrgList.remove(vo); 298 | } 299 | } 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/adapter/MainItemAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.adapter; 2 | 3 | import com.chad.library.adapter.base.BaseQuickAdapter; 4 | import com.chad.library.adapter.base.BaseViewHolder; 5 | import com.example.mydemo.R; 6 | 7 | /** 8 | * Created by jack on 2017/5/20. 9 | */ 10 | 11 | public class MainItemAdapter extends BaseQuickAdapter{ 12 | 13 | public MainItemAdapter(){ 14 | super(R.layout.list_item_main); 15 | } 16 | 17 | @Override 18 | protected void convert(BaseViewHolder helper, String item) { 19 | helper.setText(R.id.name, item); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/adapter/OrgContactAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.adapter; 2 | 3 | import android.graphics.Color; 4 | import android.view.View; 5 | import android.widget.CheckBox; 6 | import android.widget.LinearLayout; 7 | import android.widget.TextView; 8 | 9 | import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; 10 | import com.chad.library.adapter.base.BaseViewHolder; 11 | import com.chad.library.adapter.base.entity.MultiItemEntity; 12 | import com.example.mydemo.R; 13 | import com.example.mydemo.entity.AllVo; 14 | import com.example.mydemo.entity.EmpUserVo; 15 | import com.example.mydemo.entity.OrgVo; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * Created by jack on 2017/5/21. 22 | */ 23 | 24 | public class OrgContactAdapter extends BaseMultiItemQuickAdapter { 25 | 26 | public static final int ALL = 1; 27 | public static final int ORG = 2; 28 | public static final int EMP = 3; 29 | 30 | private List selectOrgList; 31 | private List selectEmpList; 32 | private List selectAllList; 33 | 34 | private List alluserList = new ArrayList<>(); 35 | 36 | public OrgContactAdapter(List data, List selectAllList, List selectOrgList, List selectEmpList){ 37 | super(data); 38 | this.selectAllList = selectAllList; 39 | this.selectOrgList = selectOrgList; 40 | this.selectEmpList = selectEmpList; 41 | addItemType(ALL, R.layout.list_item_all); 42 | addItemType(ORG, R.layout.list_item_org); 43 | addItemType(EMP, R.layout.list_item_emp); 44 | } 45 | 46 | @Override 47 | protected void convert(final BaseViewHolder helper, MultiItemEntity item) { 48 | switch (helper.getItemViewType()){ 49 | case ALL: 50 | AllVo allVo = (AllVo) item; 51 | helper.setText(R.id.tv_name, "全选"); 52 | CheckBox checkBox_all = helper.getView(R.id.checkbox); 53 | if(selectAllList.contains(allVo)){ 54 | checkBox_all.setChecked(true); 55 | }else{ 56 | checkBox_all.setChecked(false); 57 | } 58 | break; 59 | case ORG: 60 | OrgVo orgVo = (OrgVo) item; 61 | helper.setText(R.id.tv_name, ((OrgVo) item).getName()); 62 | int selectCount = getSelectUserCountByOrg(orgVo); 63 | if(selectCount==0) { 64 | helper.setText(R.id.tv_count, "(" + ((OrgVo) item).getCount() + ")"); 65 | }else{ 66 | helper.setText(R.id.tv_count, "(" + selectCount + "/" + ((OrgVo) item).getCount() + ")"); 67 | } 68 | CheckBox checkBox_org = helper.getView(R.id.checkbox); 69 | LinearLayout ll_subordinate = helper.getView(R.id.ll_subordinate); 70 | TextView tv_subordinate = helper.getView(R.id.tv_subordinate); 71 | if(selectOrgList.contains(orgVo)){ 72 | checkBox_org.setChecked(true); 73 | tv_subordinate.setTextColor(Color.BLACK); 74 | ll_subordinate.setEnabled(false); 75 | }else{ 76 | checkBox_org.setChecked(false); 77 | tv_subordinate.setTextColor(Color.BLUE); 78 | ll_subordinate.setEnabled(true); 79 | } 80 | ll_subordinate.setOnClickListener(new View.OnClickListener() { 81 | @Override 82 | public void onClick(View v) { 83 | if(onSubordinateClickListener!=null){ 84 | onSubordinateClickListener.onSubordinateClick(helper, v, helper.getAdapterPosition()); 85 | } 86 | } 87 | }); 88 | break; 89 | case EMP: 90 | EmpUserVo empUserVo = (EmpUserVo) item; 91 | helper.setText(R.id.tv_name, ((EmpUserVo) item).getName()); 92 | CheckBox checkBox_emp = helper.getView(R.id.checkbox); 93 | if(selectEmpList.contains(empUserVo)){ 94 | checkBox_emp.setChecked(true); 95 | }else{ 96 | checkBox_emp.setChecked(false); 97 | } 98 | break; 99 | } 100 | } 101 | 102 | private int getSelectUserCountByOrg(OrgVo orgVo){ 103 | int count = 0; 104 | alluserList.clear(); 105 | getAllUserByOrg(orgVo); 106 | for(EmpUserVo empUserVo : alluserList){ 107 | if(selectEmpList.contains(empUserVo)){ 108 | count++; 109 | } 110 | } 111 | return count; 112 | } 113 | 114 | private void getAllUserByOrg(OrgVo orgVo){ 115 | ArrayList orgList = orgVo.getOrgVOs(); 116 | ArrayList userList = orgVo.getUsers(); 117 | alluserList.addAll(userList); 118 | for(OrgVo vo : orgList){ 119 | getAllUserByOrg(vo); 120 | } 121 | } 122 | 123 | OnSubordinateClickListener onSubordinateClickListener; 124 | public interface OnSubordinateClickListener{ 125 | void onSubordinateClick(BaseViewHolder helper,View v,int position); 126 | } 127 | public void setOnSubordinateClickListener(OnSubordinateClickListener onSubordinateClickListener) { 128 | this.onSubordinateClickListener = onSubordinateClickListener; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/entity/AllVo.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.entity; 2 | 3 | import com.chad.library.adapter.base.entity.MultiItemEntity; 4 | import com.example.mydemo.adapter.OrgContactAdapter; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * Created by jack on 2017/5/21. 10 | */ 11 | 12 | public class AllVo implements MultiItemEntity, Serializable{ 13 | private boolean isAll; 14 | private String orgId; 15 | 16 | @Override 17 | public int getItemType() { 18 | return OrgContactAdapter.ALL; 19 | } 20 | 21 | public boolean isAll() { 22 | return isAll; 23 | } 24 | 25 | public void setAll(boolean all) { 26 | isAll = all; 27 | } 28 | 29 | public String getOrgId() { 30 | return orgId; 31 | } 32 | 33 | public void setOrgId(String orgId) { 34 | this.orgId = orgId; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object obj) { 39 | if (obj instanceof AllVo) { 40 | AllVo vo = (AllVo) obj; 41 | return (orgId.equals(vo.orgId)); 42 | } 43 | return false; 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return orgId.hashCode(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/entity/EmpUserVo.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.entity; 2 | 3 | import com.chad.library.adapter.base.entity.MultiItemEntity; 4 | import com.example.mydemo.adapter.OrgContactAdapter; 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | public class EmpUserVo implements MultiItemEntity, java.io.Serializable { 8 | 9 | private static final long serialVersionUID = 1L; 10 | private String id; 11 | @SerializedName("userName") 12 | private String name; 13 | private String account; 14 | private String sex; 15 | private String email; 16 | @SerializedName("phone") 17 | private String mobile; 18 | private String sign; 19 | @SerializedName("picture") 20 | private String photo; 21 | private String orgId; 22 | private String orgName; 23 | private String isSync;//同步标识:0:表示否; 1:表示是 24 | private String incomeDate;//入职时间 25 | private String telephone;//固定电话 26 | private String forbiddenAttribute;// 0显示添加到个人通讯录,1显示 27 | 28 | public String getTelephone() { 29 | return telephone; 30 | } 31 | 32 | public void setTelephone(String telephone) { 33 | this.telephone = telephone; 34 | } 35 | 36 | public String getIncomeDate() { 37 | return incomeDate; 38 | } 39 | 40 | public void setIncomeDate(String incomeDate) { 41 | this.incomeDate = incomeDate; 42 | } 43 | 44 | public String getId() { 45 | return id; 46 | } 47 | 48 | public void setId(String id) { 49 | this.id = id; 50 | } 51 | 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | public void setName(String name) { 57 | this.name = name; 58 | } 59 | 60 | public String getAccount() { 61 | return account; 62 | } 63 | 64 | public void setAccount(String account) { 65 | this.account = account; 66 | } 67 | 68 | public String getEmail() { 69 | return email; 70 | } 71 | 72 | public void setEmail(String email) { 73 | this.email = email; 74 | } 75 | 76 | public String getMobile() { 77 | return mobile; 78 | } 79 | 80 | public void setMobile(String mobile) { 81 | this.mobile = mobile; 82 | } 83 | 84 | public String getSign() { 85 | return sign; 86 | } 87 | 88 | public void setSign(String sign) { 89 | this.sign = sign; 90 | } 91 | 92 | public String getPhoto() { 93 | return photo; 94 | } 95 | 96 | public void setPhoto(String photo) { 97 | this.photo = photo; 98 | } 99 | 100 | public String getIsSync() { 101 | return isSync; 102 | } 103 | 104 | public void setIsSync(String isSync) { 105 | this.isSync = isSync; 106 | } 107 | 108 | public String getSex() { 109 | return sex; 110 | } 111 | 112 | public void setSex(String sex) { 113 | this.sex = sex; 114 | } 115 | 116 | public String getOrgId() { 117 | return orgId; 118 | } 119 | 120 | public void setOrgId(String orgId) { 121 | this.orgId = orgId; 122 | } 123 | 124 | public String getOrgName() { 125 | return orgName; 126 | } 127 | 128 | public void setOrgName(String orgName) { 129 | this.orgName = orgName; 130 | } 131 | 132 | public String getForbiddenAttribute() { 133 | return forbiddenAttribute; 134 | } 135 | 136 | public void setForbiddenAttribute(String forbiddenAttribute) { 137 | this.forbiddenAttribute = forbiddenAttribute; 138 | } 139 | 140 | @Override 141 | public int getItemType() { 142 | return OrgContactAdapter.EMP; 143 | } 144 | 145 | @Override 146 | public boolean equals(Object obj) { 147 | if (obj instanceof EmpUserVo) { 148 | EmpUserVo vo = (EmpUserVo) obj; 149 | return (id.equals(vo.id)); 150 | } 151 | return false; 152 | } 153 | 154 | @Override 155 | public int hashCode() { 156 | return id.hashCode(); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/entity/OrgVo.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.entity; 2 | 3 | import com.chad.library.adapter.base.entity.MultiItemEntity; 4 | import com.example.mydemo.adapter.OrgContactAdapter; 5 | 6 | import java.util.ArrayList; 7 | 8 | 9 | public class OrgVo implements MultiItemEntity, java.io.Serializable { 10 | //ZF机构 11 | private static final long serialVersionUID = 1L; 12 | private String id;//机构ID 13 | private String code;//机构编码 14 | private String name;//机构名称 15 | private String pid;//上级 16 | 17 | private String count;//部门人数 18 | private ArrayList users;//机构所属用户 19 | private ArrayList orgVOs;//下属机构 20 | 21 | private String incomeData;//入职时间 22 | private String telephone;//固话 23 | 24 | public String getIncomeData() { 25 | return incomeData; 26 | } 27 | 28 | public void setIncomeData(String incomeData) { 29 | this.incomeData = incomeData; 30 | } 31 | 32 | public String getTelephone() { 33 | return telephone; 34 | } 35 | 36 | public void setTelephone(String telephone) { 37 | this.telephone = telephone; 38 | } 39 | 40 | public static long getSerialVersionUID() { 41 | return serialVersionUID; 42 | } 43 | 44 | public String getCount() { 45 | return count; 46 | } 47 | 48 | public void setCount(String count) { 49 | this.count = count; 50 | } 51 | 52 | public String getId() { 53 | return id; 54 | } 55 | 56 | public void setId(String id) { 57 | this.id = id; 58 | } 59 | 60 | public String getCode() { 61 | return code; 62 | } 63 | 64 | public void setCode(String code) { 65 | this.code = code; 66 | } 67 | 68 | public String getName() { 69 | return name; 70 | } 71 | 72 | public void setName(String name) { 73 | this.name = name; 74 | } 75 | 76 | public String getPid() { 77 | return pid; 78 | } 79 | 80 | public void setPid(String pid) { 81 | this.pid = pid; 82 | } 83 | 84 | public ArrayList getUsers() { 85 | return users; 86 | } 87 | 88 | public void setUsers(ArrayList users) { 89 | this.users = users; 90 | } 91 | 92 | public ArrayList getOrgVOs() { 93 | return orgVOs; 94 | } 95 | 96 | public void setOrgVOs(ArrayList orgVOs) { 97 | this.orgVOs = orgVOs; 98 | } 99 | 100 | @Override 101 | public int getItemType() { 102 | return OrgContactAdapter.ORG; 103 | } 104 | 105 | @Override 106 | public boolean equals(Object obj) { 107 | if (obj instanceof OrgVo) { 108 | OrgVo vo = (OrgVo) obj; 109 | return (id.equals(vo.id)); 110 | } 111 | return false; 112 | } 113 | 114 | @Override 115 | public int hashCode() { 116 | return id.hashCode(); 117 | 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/entity/ResultVo.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by jack on 2017/5/21. 7 | */ 8 | 9 | public class ResultVo { 10 | 11 | private String errcode; 12 | 13 | private String errmsg; 14 | 15 | private Object msg; 16 | 17 | private String result; 18 | 19 | public void setErrcode(String errcode){ 20 | this.errcode = errcode; 21 | } 22 | public String getErrcode(){ 23 | return this.errcode; 24 | } 25 | public void setErrmsg(String errmsg){ 26 | this.errmsg = errmsg; 27 | } 28 | public String getErrmsg(){ 29 | return this.errmsg; 30 | } 31 | public void setMsg(Object msg){ 32 | this.msg = msg; 33 | } 34 | public Object getMsg(){ 35 | return this.msg; 36 | } 37 | public void setResult(String result){ 38 | this.result = result; 39 | } 40 | public String getResult(){ 41 | return this.result; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | import android.support.annotation.IntDef; 6 | import android.util.Log; 7 | 8 | import org.json.JSONArray; 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | import java.io.BufferedWriter; 13 | import java.io.File; 14 | import java.io.FileWriter; 15 | import java.io.IOException; 16 | import java.io.StringReader; 17 | import java.io.StringWriter; 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | import java.text.SimpleDateFormat; 21 | import java.util.Date; 22 | import java.util.Formatter; 23 | import java.util.Locale; 24 | 25 | import javax.xml.transform.OutputKeys; 26 | import javax.xml.transform.Source; 27 | import javax.xml.transform.Transformer; 28 | import javax.xml.transform.TransformerFactory; 29 | import javax.xml.transform.stream.StreamResult; 30 | import javax.xml.transform.stream.StreamSource; 31 | 32 | /** 33 | *
 34 |  *     author: Blankj
 35 |  *     blog  : http://blankj.com
 36 |  *     time  : 2016/9/21
 37 |  *     desc  : 日志相关工具类
 38 |  * 
39 | */ 40 | public final class LogUtils { 41 | 42 | private LogUtils() { 43 | throw new UnsupportedOperationException("u can't instantiate me..."); 44 | } 45 | 46 | public static final int V = 0x01; 47 | public static final int D = 0x02; 48 | public static final int I = 0x04; 49 | public static final int W = 0x08; 50 | public static final int E = 0x10; 51 | public static final int A = 0x20; 52 | 53 | @IntDef({V, D, I, W, E, A}) 54 | @Retention(RetentionPolicy.SOURCE) 55 | public @interface TYPE { 56 | } 57 | 58 | private static final int FILE = 0xF1; 59 | private static final int JSON = 0xF2; 60 | private static final int XML = 0xF4; 61 | 62 | private static String dir; // log存储目录 63 | private static boolean sLogSwitch = true; // log总开关 64 | private static String sGlobalTag = null; // log标签 65 | private static boolean sTagIsSpace = true; // log标签是否为空白 66 | private static boolean sLog2FileSwitch = false;// log写入文件开关 67 | private static boolean sLogBorderSwitch = true; // log边框开关 68 | private static int sLogFilter = V; // log过滤器 69 | 70 | private static final String TOP_BORDER = "╔═══════════════════════════════════════════════════════════════════════════════════════════════════"; 71 | private static final String LEFT_BORDER = "║ "; 72 | private static final String BOTTOM_BORDER = "╚═══════════════════════════════════════════════════════════════════════════════════════════════════"; 73 | private static final String LINE_SEPARATOR = System.getProperty("line.separator"); 74 | 75 | private static final int MAX_LEN = 4000; 76 | private static final String NULL_TIPS = "Log with null object."; 77 | private static final String NULL = "null"; 78 | private static final String ARGS = "args"; 79 | 80 | public static class Builder { 81 | 82 | public Builder(Context context) { 83 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { 84 | dir = context.getExternalCacheDir() + File.separator + "log" + File.separator; 85 | } else { 86 | dir = context.getCacheDir() + File.separator + "log" + File.separator; 87 | } 88 | } 89 | 90 | public Builder setGlobalTag(String tag) { 91 | if (!isSpace(tag)) { 92 | LogUtils.sGlobalTag = tag; 93 | sTagIsSpace = false; 94 | } else { 95 | LogUtils.sGlobalTag = ""; 96 | sTagIsSpace = true; 97 | } 98 | return this; 99 | } 100 | 101 | public Builder setLogSwitch(boolean logSwitch) { 102 | LogUtils.sLogSwitch = logSwitch; 103 | return this; 104 | } 105 | 106 | public Builder setLog2FileSwitch(boolean log2FileSwitch) { 107 | LogUtils.sLog2FileSwitch = log2FileSwitch; 108 | return this; 109 | } 110 | 111 | public Builder setBorderSwitch(boolean borderSwitch) { 112 | LogUtils.sLogBorderSwitch = borderSwitch; 113 | return this; 114 | } 115 | 116 | public Builder setLogFilter(@TYPE int logFilter) { 117 | LogUtils.sLogFilter = logFilter; 118 | return this; 119 | } 120 | } 121 | 122 | public static void v(Object contents) { 123 | log(V, sGlobalTag, contents); 124 | } 125 | 126 | public static void v(String tag, Object... contents) { 127 | log(V, tag, contents); 128 | } 129 | 130 | public static void d(Object contents) { 131 | log(D, sGlobalTag, contents); 132 | } 133 | 134 | public static void d(String tag, Object... contents) { 135 | log(D, tag, contents); 136 | } 137 | 138 | public static void i(Object contents) { 139 | log(I, sGlobalTag, contents); 140 | } 141 | 142 | public static void i(String tag, Object... contents) { 143 | log(I, tag, contents); 144 | } 145 | 146 | public static void w(Object contents) { 147 | log(W, sGlobalTag, contents); 148 | } 149 | 150 | public static void w(String tag, Object... contents) { 151 | log(W, tag, contents); 152 | } 153 | 154 | public static void e(Object contents) { 155 | log(E, sGlobalTag, contents); 156 | } 157 | 158 | public static void e(String tag, Object... contents) { 159 | log(E, tag, contents); 160 | } 161 | 162 | public static void a(Object contents) { 163 | log(A, sGlobalTag, contents); 164 | } 165 | 166 | public static void a(String tag, Object... contents) { 167 | log(A, tag, contents); 168 | } 169 | 170 | public static void file(Object contents) { 171 | log(FILE, sGlobalTag, contents); 172 | } 173 | 174 | public static void file(String tag, Object contents) { 175 | log(FILE, tag, contents); 176 | } 177 | 178 | public static void json(String contents) { 179 | log(JSON, sGlobalTag, contents); 180 | } 181 | 182 | public static void json(String tag, String contents) { 183 | log(JSON, tag, contents); 184 | } 185 | 186 | public static void xml(String contents) { 187 | log(XML, sGlobalTag, contents); 188 | } 189 | 190 | public static void xml(String tag, String contents) { 191 | log(XML, tag, contents); 192 | } 193 | 194 | private static void log(int type, String tag, Object... contents) { 195 | if (!sLogSwitch) return; 196 | final String[] processContents = processContents(type, tag, contents); 197 | tag = processContents[0]; 198 | String msg = processContents[1]; 199 | switch (type) { 200 | case V: 201 | case D: 202 | case I: 203 | case W: 204 | case E: 205 | case A: 206 | if (V == sLogFilter || type >= sLogFilter) { 207 | printLog(type, tag, msg); 208 | } 209 | if (sLog2FileSwitch) { 210 | print2File(tag, msg); 211 | } 212 | break; 213 | case FILE: 214 | print2File(tag, msg); 215 | break; 216 | case JSON: 217 | printLog(D, tag, msg); 218 | break; 219 | case XML: 220 | printLog(D, tag, msg); 221 | break; 222 | } 223 | 224 | } 225 | 226 | private static String[] processContents(int type, String tag, Object... contents) { 227 | StackTraceElement targetElement = Thread.currentThread().getStackTrace()[5]; 228 | String className = targetElement.getClassName(); 229 | String[] classNameInfo = className.split("\\."); 230 | if (classNameInfo.length > 0) { 231 | className = classNameInfo[classNameInfo.length - 1]; 232 | } 233 | if (className.contains("$")) { 234 | className = className.split("\\$")[0]; 235 | } 236 | if (!sTagIsSpace) {// 如果全局tag不为空,那就用全局tag 237 | tag = sGlobalTag; 238 | } else {// 全局tag为空时,如果传入的tag为空那就显示类名,否则显示tag 239 | tag = isSpace(tag) ? className : tag; 240 | } 241 | 242 | String head = new Formatter() 243 | .format("Thread: %s, %s(%s.java:%d)" + LINE_SEPARATOR, 244 | Thread.currentThread().getName(), 245 | targetElement.getMethodName(), 246 | className, 247 | targetElement.getLineNumber()) 248 | .toString(); 249 | String msg = NULL_TIPS; 250 | if (contents != null) { 251 | if (contents.length == 1) { 252 | Object object = contents[0]; 253 | msg = object == null ? NULL : object.toString(); 254 | if (type == JSON) { 255 | msg = formatJson(msg); 256 | } else if (type == XML) { 257 | msg = formatXml(msg); 258 | } 259 | } else { 260 | StringBuilder sb = new StringBuilder(); 261 | for (int i = 0, len = contents.length; i < len; ++i) { 262 | Object content = contents[i]; 263 | sb.append(ARGS) 264 | .append("[") 265 | .append(i) 266 | .append("]") 267 | .append(" = ") 268 | .append(content == null ? NULL : content.toString()) 269 | .append(LINE_SEPARATOR); 270 | } 271 | msg = sb.toString(); 272 | } 273 | } 274 | if (sLogBorderSwitch) { 275 | StringBuilder sb = new StringBuilder(); 276 | String[] lines = msg.split(LINE_SEPARATOR); 277 | for (String line : lines) { 278 | sb.append(LEFT_BORDER).append(line).append(LINE_SEPARATOR); 279 | } 280 | msg = sb.toString(); 281 | } 282 | return new String[]{tag, head + msg}; 283 | } 284 | 285 | private static String formatJson(String json) { 286 | try { 287 | if (json.startsWith("{")) { 288 | json = new JSONObject(json).toString(4); 289 | } else if (json.startsWith("[")) { 290 | json = new JSONArray(json).toString(4); 291 | } 292 | } catch (JSONException e) { 293 | e.printStackTrace(); 294 | } 295 | return json; 296 | } 297 | 298 | private static String formatXml(String xml) { 299 | try { 300 | Source xmlInput = new StreamSource(new StringReader(xml)); 301 | StreamResult xmlOutput = new StreamResult(new StringWriter()); 302 | Transformer transformer = TransformerFactory.newInstance().newTransformer(); 303 | transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 304 | transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 305 | transformer.transform(xmlInput, xmlOutput); 306 | xml = xmlOutput.getWriter().toString().replaceFirst(">", ">" + LINE_SEPARATOR); 307 | } catch (Exception e) { 308 | e.printStackTrace(); 309 | } 310 | return xml; 311 | } 312 | 313 | private static void printLog(int type, String tag, String msg) { 314 | if (sLogBorderSwitch) printBorder(type, tag, true); 315 | int len = msg.length(); 316 | int countOfSub = len / MAX_LEN; 317 | if (countOfSub > 0) { 318 | int index = 0; 319 | String sub; 320 | for (int i = 0; i < countOfSub; i++) { 321 | sub = msg.substring(index, index + MAX_LEN); 322 | printSubLog(type, tag, sub); 323 | index += MAX_LEN; 324 | } 325 | printSubLog(type, tag, msg.substring(index, len)); 326 | } else { 327 | printSubLog(type, tag, msg); 328 | } 329 | if (sLogBorderSwitch) printBorder(type, tag, false); 330 | } 331 | 332 | private static void printSubLog(final int type, final String tag, String msg) { 333 | if (sLogBorderSwitch) msg = LEFT_BORDER + msg; 334 | switch (type) { 335 | case V: 336 | Log.v(tag, msg); 337 | break; 338 | case D: 339 | Log.d(tag, msg); 340 | break; 341 | case I: 342 | Log.i(tag, msg); 343 | break; 344 | case W: 345 | Log.w(tag, msg); 346 | break; 347 | case E: 348 | Log.e(tag, msg); 349 | break; 350 | case A: 351 | Log.wtf(tag, msg); 352 | break; 353 | } 354 | } 355 | 356 | private static void printBorder(int type, String tag, boolean isTop) { 357 | String border = isTop ? TOP_BORDER : BOTTOM_BORDER; 358 | switch (type) { 359 | case V: 360 | Log.v(tag, border); 361 | break; 362 | case D: 363 | Log.d(tag, border); 364 | break; 365 | case I: 366 | Log.i(tag, border); 367 | break; 368 | case W: 369 | Log.w(tag, border); 370 | break; 371 | case E: 372 | Log.e(tag, border); 373 | break; 374 | case A: 375 | Log.wtf(tag, border); 376 | break; 377 | } 378 | } 379 | 380 | private synchronized static void print2File(final String tag, final String msg) { 381 | Date now = new Date(); 382 | String date = new SimpleDateFormat("MM-dd", Locale.getDefault()).format(now); 383 | final String fullPath = dir + date + ".txt"; 384 | if (!createOrExistsFile(fullPath)) { 385 | Log.e(tag, "log to " + fullPath + " failed!"); 386 | return; 387 | } 388 | String time = new SimpleDateFormat("MM-dd HH:mm:ss.SSS ", Locale.getDefault()).format(now); 389 | StringBuilder sb = new StringBuilder(); 390 | if (sLogBorderSwitch) sb.append(TOP_BORDER).append(LINE_SEPARATOR); 391 | sb.append(time) 392 | .append(tag) 393 | .append(": ") 394 | .append(msg) 395 | .append(LINE_SEPARATOR); 396 | if (sLogBorderSwitch) sb.append(BOTTOM_BORDER).append(LINE_SEPARATOR); 397 | final String dateLogContent = sb.toString(); 398 | new Thread(new Runnable() { 399 | @Override 400 | public void run() { 401 | BufferedWriter bw = null; 402 | try { 403 | bw = new BufferedWriter(new FileWriter(fullPath, true)); 404 | bw.write(dateLogContent); 405 | Log.d(tag, "log to " + fullPath + " success!"); 406 | } catch (IOException e) { 407 | e.printStackTrace(); 408 | Log.e(tag, "log to " + fullPath + " failed!"); 409 | } finally { 410 | try { 411 | if (bw != null) { 412 | bw.close(); 413 | } 414 | } catch (IOException e) { 415 | e.printStackTrace(); 416 | } 417 | } 418 | } 419 | }).start(); 420 | } 421 | 422 | private static boolean createOrExistsFile(String filePath) { 423 | return createOrExistsFile(isSpace(filePath) ? null : new File(filePath)); 424 | } 425 | 426 | private static boolean createOrExistsFile(File file) { 427 | if (file == null) return false; 428 | if (file.exists()) return file.isFile(); 429 | if (!createOrExistsDir(file.getParentFile())) return false; 430 | try { 431 | return file.createNewFile(); 432 | } catch (IOException e) { 433 | e.printStackTrace(); 434 | return false; 435 | } 436 | } 437 | 438 | private static boolean createOrExistsDir(File file) { 439 | return file != null && (file.exists() ? file.isDirectory() : file.mkdirs()); 440 | } 441 | 442 | private static boolean isSpace(String s) { 443 | if (s == null) return true; 444 | for (int i = 0, len = s.length(); i < len; ++i) { 445 | if (!Character.isWhitespace(s.charAt(i))) { 446 | return false; 447 | } 448 | } 449 | return true; 450 | } 451 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/mydemo/view/RecyclerViewItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.example.mydemo.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.DashPathEffect; 9 | import android.graphics.NinePatch; 10 | import android.graphics.Paint; 11 | import android.graphics.Path; 12 | import android.graphics.PathEffect; 13 | import android.graphics.Rect; 14 | import android.support.annotation.ColorInt; 15 | import android.support.v7.widget.GridLayoutManager; 16 | import android.support.v7.widget.RecyclerView; 17 | import android.view.View; 18 | 19 | import java.util.regex.Pattern; 20 | 21 | /** 22 | * RecycleView item decoration 23 | * Created by Eminem Lu on 24/11/15. 24 | * Email arjinmc@hotmail.com 25 | * https://github.com/arjinmc/RecyclerViewDecoration 26 | */ 27 | public class RecyclerViewItemDecoration extends RecyclerView.ItemDecoration { 28 | 29 | /** 30 | * mode for direction 31 | */ 32 | public static final int MODE_HORIZONTAL = 0; 33 | public static final int MODE_VERTICAL = 1; 34 | public static final int MODE_GRID = 2; 35 | 36 | /** 37 | * default decoration color 38 | */ 39 | private static final String DEFAULT_COLOR = "#bdbdbd"; 40 | 41 | /** 42 | * image resource id for R.java 43 | */ 44 | private int mDrawableRid = 0; 45 | /** 46 | * decoration color 47 | */ 48 | private int mColor = Color.parseColor(DEFAULT_COLOR); 49 | /** 50 | * decoration thickness 51 | */ 52 | private int mThickness; 53 | /** 54 | * decoration dash with 55 | */ 56 | private int mDashWidth = 0; 57 | /** 58 | * decoration dash gap 59 | */ 60 | private int mDashGap = 0; 61 | private boolean mFirstLineVisible; 62 | private boolean mLastLineVisible; 63 | private int mPaddingStart = 0; 64 | private int mPaddingEnd = 0; 65 | /** 66 | * direction mode for decoration 67 | */ 68 | private int mMode; 69 | 70 | private Paint mPaint; 71 | 72 | private Bitmap mBmp; 73 | private NinePatch mNinePatch; 74 | /** 75 | * choose the real thickness for image or thickness 76 | */ 77 | private int mCurrentThickness; 78 | /** 79 | * sign for if the resource image is a ninepatch image 80 | */ 81 | private Boolean hasNinePatch = false; 82 | 83 | public RecyclerViewItemDecoration() { 84 | } 85 | 86 | @Deprecated 87 | public RecyclerViewItemDecoration(int recyclerviewMode, Context context, int drawableRid) { 88 | this.mMode = recyclerviewMode; 89 | this.mDrawableRid = drawableRid; 90 | 91 | this.mBmp = BitmapFactory.decodeResource(context.getResources(), drawableRid); 92 | if (mBmp.getNinePatchChunk() != null) { 93 | hasNinePatch = true; 94 | mNinePatch = new NinePatch(mBmp, mBmp.getNinePatchChunk(), null); 95 | } 96 | initPaint(); 97 | 98 | } 99 | 100 | @Deprecated 101 | public RecyclerViewItemDecoration(int recyclerviewMode, int color, int thick, int dashWidth, int dashGap) { 102 | this.mMode = recyclerviewMode; 103 | this.mColor = color; 104 | this.mThickness = thick; 105 | this.mDashWidth = dashWidth; 106 | this.mDashGap = dashGap; 107 | 108 | initPaint(); 109 | 110 | } 111 | 112 | @Deprecated 113 | public RecyclerViewItemDecoration(int recyclerviewMode, String color, int thick, int dashWidth, int dashGap) { 114 | this.mMode = recyclerviewMode; 115 | if (isColorString(color)) { 116 | this.mColor = Color.parseColor(color); 117 | } else { 118 | this.mColor = Color.parseColor(DEFAULT_COLOR); 119 | } 120 | this.mThickness = thick; 121 | this.mDashWidth = dashWidth; 122 | this.mDashGap = dashGap; 123 | 124 | initPaint(); 125 | } 126 | 127 | public void setParams(Context context, Param params) { 128 | 129 | this.mMode = params.mode; 130 | this.mDrawableRid = params.drawableRid; 131 | this.mColor = params.color; 132 | this.mThickness = params.thickness; 133 | this.mDashGap = params.dashGap; 134 | this.mDashWidth = params.dashWidth; 135 | this.mPaddingStart = params.paddingStart; 136 | this.mPaddingEnd = params.paddingEnd; 137 | this.mFirstLineVisible = params.firstLineVisible; 138 | this.mLastLineVisible = params.lastLineVisible; 139 | 140 | this.mBmp = BitmapFactory.decodeResource(context.getResources(), mDrawableRid); 141 | if (mBmp != null) { 142 | 143 | if (mBmp.getNinePatchChunk() != null) { 144 | hasNinePatch = true; 145 | mNinePatch = new NinePatch(mBmp, mBmp.getNinePatchChunk(), null); 146 | } 147 | 148 | if (mMode == MODE_HORIZONTAL) 149 | mCurrentThickness = mThickness == 0 ? mBmp.getHeight() : mThickness; 150 | if (mMode == MODE_VERTICAL) 151 | mCurrentThickness = mThickness == 0 ? mBmp.getWidth() : mThickness; 152 | } 153 | 154 | initPaint(); 155 | 156 | } 157 | 158 | private void initPaint() { 159 | mPaint = new Paint(); 160 | mPaint.setColor(mColor); 161 | mPaint.setStyle(Paint.Style.STROKE); 162 | mPaint.setStrokeWidth(mThickness); 163 | } 164 | 165 | 166 | @Override 167 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 168 | 169 | mPaint.setColor(mColor); 170 | if (mMode == MODE_HORIZONTAL) { 171 | drawHorinzonal(c, parent); 172 | } else if (mMode == MODE_VERTICAL) { 173 | drawVertical(c, parent); 174 | } else if (mMode == MODE_GRID) { 175 | drawGrid(c, parent); 176 | } 177 | } 178 | 179 | @Override 180 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 181 | 182 | if (mMode == MODE_HORIZONTAL) { 183 | 184 | if (!(!mLastLineVisible && 185 | parent.getChildLayoutPosition(view) == parent.getAdapter().getItemCount() - 1)) { 186 | if (mDrawableRid != 0) { 187 | outRect.set(0, 0, 0, mCurrentThickness); 188 | } else { 189 | outRect.set(0, 0, 0, mThickness); 190 | } 191 | } 192 | 193 | if (mFirstLineVisible && parent.getChildLayoutPosition(view) == 0) { 194 | if (mDrawableRid != 0) { 195 | outRect.set(0, mCurrentThickness, 0, mCurrentThickness); 196 | } else { 197 | outRect.set(0, mThickness, 0, mThickness); 198 | } 199 | } 200 | 201 | } else if (mMode == MODE_VERTICAL) { 202 | if (!(!mLastLineVisible && 203 | parent.getChildLayoutPosition(view) == parent.getAdapter().getItemCount() - 1)) { 204 | if (mDrawableRid != 0) { 205 | outRect.set(0, 0, mCurrentThickness, 0); 206 | } else { 207 | outRect.set(0, 0, mThickness, 0); 208 | } 209 | } 210 | if (mFirstLineVisible && parent.getChildLayoutPosition(view) == 0) { 211 | if (mDrawableRid != 0) { 212 | outRect.set(mCurrentThickness, 0, mCurrentThickness, 0); 213 | } else { 214 | outRect.set(mThickness, 0, mThickness, 0); 215 | } 216 | } 217 | 218 | } else if (mMode == MODE_GRID) { 219 | int columnSize = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount(); 220 | int itemSzie = parent.getAdapter().getItemCount(); 221 | if (mDrawableRid != 0) { 222 | if (isLastRowGrid(parent.getChildLayoutPosition(view), itemSzie, columnSize) 223 | && isLastGridColumn(parent.getChildLayoutPosition(view), columnSize)) { 224 | outRect.set(0, 0, 0, 0); 225 | } else if (isLastRowGrid(parent.getChildLayoutPosition(view), itemSzie, columnSize)) { 226 | outRect.set(0, 0, mBmp.getWidth(), 0); 227 | } else if ((parent.getChildLayoutPosition(view) + 1) % columnSize != 0) { 228 | outRect.set(0, 0, mBmp.getWidth(), mBmp.getHeight()); 229 | } else { 230 | outRect.set(0, 0, 0, mBmp.getHeight()); 231 | } 232 | } else { 233 | if (isLastRowGrid(parent.getChildLayoutPosition(view), itemSzie, columnSize) 234 | && isLastGridColumn(parent.getChildLayoutPosition(view), columnSize)) { 235 | outRect.set(0, 0, 0, 0); 236 | } else if (isLastRowGrid(parent.getChildLayoutPosition(view), itemSzie, columnSize)) { 237 | outRect.set(0, 0, mThickness, 0); 238 | } else if ((parent.getChildLayoutPosition(view) + 1) % columnSize != 0) { 239 | outRect.set(0, 0, mThickness, mThickness); 240 | } else { 241 | outRect.set(0, 0, 0, mThickness); 242 | } 243 | 244 | } 245 | } 246 | 247 | } 248 | 249 | /** 250 | * judge is a color string like #xxxxxx or #xxxxxxxx 251 | * 252 | * @param colorStr 253 | * @return 254 | */ 255 | public static boolean isColorString(String colorStr) { 256 | return Pattern.matches("^#([0-9a-fA-F]{6}||[0-9a-fA-F]{8})$", colorStr); 257 | } 258 | 259 | private boolean isPureLine() { 260 | if (mDashGap == 0 && mDashWidth == 0) 261 | return true; 262 | return false; 263 | } 264 | 265 | /** 266 | * draw horizonal decoration 267 | * 268 | * @param c 269 | * @param parent 270 | */ 271 | private void drawHorinzonal(Canvas c, RecyclerView parent) { 272 | int childrentCount = parent.getChildCount(); 273 | 274 | if (mDrawableRid != 0) { 275 | 276 | if (mFirstLineVisible) { 277 | View childView = parent.getChildAt(0); 278 | int myY = childView.getTop(); 279 | 280 | if (hasNinePatch) { 281 | Rect rect = new Rect(mPaddingStart, myY - mCurrentThickness, parent.getWidth() - mPaddingEnd, myY); 282 | mNinePatch.draw(c, rect); 283 | } else { 284 | c.drawBitmap(mBmp, mPaddingStart, myY - mCurrentThickness, mPaint); 285 | } 286 | } 287 | 288 | for (int i = 0; i < childrentCount; i++) { 289 | if (!mLastLineVisible && i == childrentCount - 1) 290 | break; 291 | View childView = parent.getChildAt(i); 292 | int myY = childView.getBottom(); 293 | 294 | if (hasNinePatch) { 295 | Rect rect = new Rect(mPaddingStart, myY, parent.getWidth() - mPaddingEnd, myY + mCurrentThickness); 296 | mNinePatch.draw(c, rect); 297 | } else { 298 | c.drawBitmap(mBmp, mPaddingStart, myY, mPaint); 299 | } 300 | 301 | } 302 | 303 | } else { 304 | 305 | boolean isPureLine = isPureLine(); 306 | if (!isPureLine) { 307 | PathEffect effects = new DashPathEffect(new float[]{0, 0, mDashWidth, mThickness}, mDashGap); 308 | mPaint.setPathEffect(effects); 309 | } 310 | 311 | if (mFirstLineVisible) { 312 | View childView = parent.getChildAt(0); 313 | int myY = childView.getTop() - mThickness/ 2 ; 314 | 315 | if (isPureLine) { 316 | c.drawLine(mPaddingStart, myY, parent.getWidth() - mPaddingEnd, myY, mPaint); 317 | } else { 318 | Path path = new Path(); 319 | path.moveTo(mPaddingStart, myY); 320 | path.lineTo(parent.getWidth() - mPaddingEnd, myY); 321 | c.drawPath(path, mPaint); 322 | } 323 | } 324 | 325 | for (int i = 0; i < childrentCount; i++) { 326 | if (!mLastLineVisible && i == childrentCount - 1) 327 | break; 328 | View childView = parent.getChildAt(i); 329 | int myY = childView.getBottom() + mThickness / 2; 330 | 331 | if (isPureLine) { 332 | c.drawLine(mPaddingStart, myY, parent.getWidth() - mPaddingEnd, myY, mPaint); 333 | } else { 334 | Path path = new Path(); 335 | path.moveTo(mPaddingStart, myY); 336 | path.lineTo(parent.getWidth() - mPaddingEnd, myY); 337 | c.drawPath(path, mPaint); 338 | } 339 | 340 | } 341 | 342 | } 343 | } 344 | 345 | /** 346 | * draw vertival decoration 347 | * 348 | * @param c 349 | * @param parent 350 | */ 351 | private void drawVertical(Canvas c, RecyclerView parent) { 352 | int childrentCount = parent.getChildCount(); 353 | if (mDrawableRid != 0) { 354 | 355 | if (mFirstLineVisible) { 356 | View childView = parent.getChildAt(0); 357 | int myX = childView.getLeft(); 358 | if (hasNinePatch) { 359 | Rect rect = new Rect(myX - mCurrentThickness, mPaddingStart, myX, parent.getHeight() - mPaddingEnd); 360 | mNinePatch.draw(c, rect); 361 | } else { 362 | c.drawBitmap(mBmp, myX - mCurrentThickness, mPaddingStart, mPaint); 363 | } 364 | } 365 | for (int i = 0; i < childrentCount; i++) { 366 | if (!mLastLineVisible && i == childrentCount - 1) 367 | break; 368 | View childView = parent.getChildAt(i); 369 | int myX = childView.getRight(); 370 | if (hasNinePatch) { 371 | Rect rect = new Rect(myX, mPaddingStart, myX + mCurrentThickness, parent.getHeight() - mPaddingEnd); 372 | mNinePatch.draw(c, rect); 373 | } else { 374 | c.drawBitmap(mBmp, myX, mPaddingStart, mPaint); 375 | } 376 | } 377 | 378 | } else { 379 | 380 | boolean isPureLine = isPureLine(); 381 | if (!isPureLine) { 382 | PathEffect effects = new DashPathEffect(new float[]{0, 0, mDashWidth, mThickness}, mDashGap); 383 | mPaint.setPathEffect(effects); 384 | } 385 | 386 | if (mFirstLineVisible) { 387 | View childView = parent.getChildAt(0); 388 | int myX = childView.getLeft() - mThickness / 2; 389 | if (isPureLine) { 390 | c.drawLine(myX, mPaddingStart, myX, parent.getHeight() - mPaddingEnd, mPaint); 391 | } else { 392 | Path path = new Path(); 393 | path.moveTo(myX, mPaddingStart); 394 | path.lineTo(myX, parent.getHeight() - mPaddingEnd); 395 | c.drawPath(path, mPaint); 396 | } 397 | } 398 | 399 | for (int i = 0; i < childrentCount; i++) { 400 | if (!mLastLineVisible && i == childrentCount - 1) 401 | break; 402 | View childView = parent.getChildAt(i); 403 | int myX = childView.getRight() + mThickness / 2; 404 | if (isPureLine) { 405 | c.drawLine(myX, mPaddingStart, myX, parent.getHeight() - mPaddingEnd, mPaint); 406 | } else { 407 | Path path = new Path(); 408 | path.moveTo(myX, mPaddingStart); 409 | path.lineTo(myX, parent.getHeight() - mPaddingEnd); 410 | c.drawPath(path, mPaint); 411 | } 412 | 413 | } 414 | } 415 | } 416 | 417 | /** 418 | * draw grid decoration 419 | * 420 | * @param c 421 | * @param parent 422 | */ 423 | private void drawGrid(Canvas c, RecyclerView parent) { 424 | 425 | int childrentCount = parent.getChildCount(); 426 | int columnSize = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount(); 427 | int adapterChildrenCount = parent.getAdapter().getItemCount(); 428 | 429 | if (mDrawableRid != 0) { 430 | if (hasNinePatch) { 431 | for (int i = 0; i < childrentCount; i++) { 432 | View childView = parent.getChildAt(i); 433 | int myX = childView.getRight(); 434 | int myY = childView.getBottom(); 435 | 436 | //horizonal 437 | if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) { 438 | Rect rect = new Rect(0, myY, myX, myY + mBmp.getHeight()); 439 | mNinePatch.draw(c, rect); 440 | } 441 | 442 | //vertical 443 | if (isLastRowGrid(i, adapterChildrenCount, columnSize) 444 | && !isLastGridColumn(i, columnSize)) { 445 | Rect rect = new Rect(myX, childView.getTop(), myX + mBmp.getWidth(), myY); 446 | mNinePatch.draw(c, rect); 447 | } else if (!isLastGridColumn(i, columnSize)) { 448 | Rect rect = new Rect(myX, childView.getTop(), myX + mBmp.getWidth(), myY + mBmp.getHeight()); 449 | mNinePatch.draw(c, rect); 450 | } 451 | 452 | } 453 | } else { 454 | 455 | for (int i = 0; i < childrentCount; i++) { 456 | View childView = parent.getChildAt(i); 457 | int myX = childView.getRight(); 458 | int myY = childView.getBottom(); 459 | 460 | //horizonal 461 | if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) { 462 | c.drawBitmap(mBmp, childView.getLeft(), myY, mPaint); 463 | } 464 | 465 | //vertical 466 | if (!isLastGridColumn(i, columnSize)) { 467 | c.drawBitmap(mBmp, myX, childView.getTop(), mPaint); 468 | } 469 | 470 | 471 | } 472 | } 473 | } else if (mDashWidth == 0 && mDashGap == 0) { 474 | 475 | for (int i = 0; i < childrentCount; i++) { 476 | View childView = parent.getChildAt(i); 477 | int myX = childView.getRight() + mThickness / 2; 478 | int myY = childView.getBottom() + mThickness / 2; 479 | 480 | //horizonal 481 | if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) { 482 | c.drawLine(childView.getLeft(), myY, childView.getRight() + mThickness, myY, mPaint); 483 | } 484 | 485 | //vertical 486 | if (isLastRowGrid(i, adapterChildrenCount, columnSize) 487 | && !isLastGridColumn(i, columnSize)) { 488 | c.drawLine(myX, childView.getTop(), myX, childView.getBottom(), mPaint); 489 | } else if (!isLastGridColumn(i, columnSize)) { 490 | c.drawLine(myX, childView.getTop(), myX, myY, mPaint); 491 | } 492 | 493 | } 494 | 495 | 496 | } else { 497 | PathEffect effects = new DashPathEffect(new float[]{0, 0, mDashWidth, mThickness}, mDashGap); 498 | mPaint.setPathEffect(effects); 499 | for (int i = 0; i < childrentCount; i++) { 500 | View childView = parent.getChildAt(i); 501 | int myX = childView.getRight() + mThickness / 2; 502 | int myY = childView.getBottom() + mThickness / 2; 503 | 504 | //horizonal 505 | if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) { 506 | Path path = new Path(); 507 | path.moveTo(0, myY); 508 | path.lineTo(myX, myY); 509 | c.drawPath(path, mPaint); 510 | } 511 | 512 | //vertical 513 | if (isLastRowGrid(i, adapterChildrenCount, columnSize) 514 | && !isLastGridColumn(i, columnSize)) { 515 | Path path = new Path(); 516 | path.moveTo(myX, childView.getTop()); 517 | path.lineTo(myX, childView.getBottom()); 518 | c.drawPath(path, mPaint); 519 | } else if (!isLastGridColumn(i, columnSize)) { 520 | Path path = new Path(); 521 | path.moveTo(myX, childView.getTop()); 522 | path.lineTo(myX, childView.getBottom()); 523 | c.drawPath(path, mPaint); 524 | } 525 | 526 | } 527 | } 528 | } 529 | 530 | /** 531 | * check if is one of the last columns 532 | * 533 | * @param position 534 | * @param columnSize 535 | * @return 536 | */ 537 | private boolean isLastGridColumn(int position, int columnSize) { 538 | boolean isLast = false; 539 | if ((position + 1) % columnSize == 0) { 540 | isLast = true; 541 | } 542 | return isLast; 543 | } 544 | 545 | /** 546 | * check if is the last row of the grid 547 | * 548 | * @param position 549 | * @param itemSize 550 | * @param columnSize 551 | * @return 552 | */ 553 | private boolean isLastRowGrid(int position, int itemSize, int columnSize) { 554 | return position / columnSize == (itemSize - 1) / columnSize; 555 | } 556 | 557 | public static class Builder { 558 | 559 | private Param params; 560 | private Context context; 561 | 562 | public Builder(Context context) { 563 | 564 | params = new Param(); 565 | this.context = context; 566 | 567 | } 568 | 569 | public RecyclerViewItemDecoration create() { 570 | RecyclerViewItemDecoration recyclerViewItemDecoration = new RecyclerViewItemDecoration(); 571 | recyclerViewItemDecoration.setParams(context, params); 572 | return recyclerViewItemDecoration; 573 | } 574 | 575 | public Builder mode(int mode) { 576 | params.mode = mode; 577 | return this; 578 | } 579 | 580 | public Builder drawableID(int drawableID) { 581 | params.drawableRid = drawableID; 582 | return this; 583 | } 584 | 585 | public Builder color(@ColorInt int color) { 586 | params.color = color; 587 | return this; 588 | } 589 | 590 | public Builder color(String color) { 591 | if (isColorString(color)) { 592 | params.color = Color.parseColor(color); 593 | } 594 | return this; 595 | } 596 | 597 | public Builder thickness(int thickness) { 598 | params.thickness = thickness; 599 | return this; 600 | } 601 | 602 | public Builder dashWidth(int dashWidth) { 603 | params.dashWidth = dashWidth; 604 | return this; 605 | } 606 | 607 | public Builder dashGap(int dashGap) { 608 | params.dashGap = dashGap; 609 | return this; 610 | } 611 | 612 | public Builder lastLineVisible(boolean visible) { 613 | params.lastLineVisible = visible; 614 | return this; 615 | } 616 | 617 | public Builder firstLineVisible(boolean visible) { 618 | params.firstLineVisible = visible; 619 | return this; 620 | } 621 | 622 | public Builder paddingStart(int padding) { 623 | params.paddingStart = padding; 624 | return this; 625 | } 626 | 627 | public Builder paddingEnd(int padding) { 628 | params.paddingEnd = padding; 629 | return this; 630 | } 631 | } 632 | 633 | private static class Param { 634 | 635 | public int mode = MODE_HORIZONTAL; 636 | public int drawableRid = 0; 637 | public int color = Color.parseColor(DEFAULT_COLOR); 638 | public int thickness; 639 | public int dashWidth = 0; 640 | public int dashGap = 0; 641 | public boolean lastLineVisible; 642 | public boolean firstLineVisible; 643 | public int paddingStart; 644 | public int paddingEnd; 645 | } 646 | 647 | } 648 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/common_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShallowMeet/OrganizeSelectionDemo/ed3746f64e35ce807edad14af41f83ee821e7e82/app/src/main/res/drawable-xhdpi/common_arrow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_org_contact.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 18 | 19 | 20 | 21 | 26 | 27 | 28 | 34 | 38 |