├── app ├── .gitignore ├── libs │ └── pinyin4j-2.5.0.jar ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── styles.xml │ │ │ │ └── attrs.xml │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── yuan.png │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── 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-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── drawable │ │ │ │ ├── bg_sidebar.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── menu │ │ │ │ └── menu_search_view.xml │ │ │ ├── layout │ │ │ │ ├── item_index.xml │ │ │ │ ├── activity_country3.xml │ │ │ │ ├── activity_country32.xml │ │ │ │ ├── activity_country1.xml │ │ │ │ ├── activity_country4.xml │ │ │ │ ├── activity_country2.xml │ │ │ │ ├── activity_country5.xml │ │ │ │ ├── item_country.xml │ │ │ │ └── activity_main.xml │ │ │ └── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── lp │ │ │ │ └── sidebar_master │ │ │ │ ├── base │ │ │ │ ├── BaseContent.java │ │ │ │ ├── api │ │ │ │ │ ├── Fields.java │ │ │ │ │ ├── ApiServer.java │ │ │ │ │ └── ApiRetrofit.java │ │ │ │ ├── mvp │ │ │ │ │ ├── BaseView.java │ │ │ │ │ ├── BaseModel.java │ │ │ │ │ ├── BasePresenter.java │ │ │ │ │ └── BaseObserver.java │ │ │ │ ├── viewholder │ │ │ │ │ ├── CommonAdapter.java │ │ │ │ │ └── ViewHolder.java │ │ │ │ └── BaseActivity.java │ │ │ │ ├── presenter │ │ │ │ ├── CountryView.java │ │ │ │ ├── CountryPresenter.java │ │ │ │ └── CountryBean.java │ │ │ │ ├── adapter │ │ │ │ ├── CountryLvAdapter.java │ │ │ │ └── CountryRvAdapter.java │ │ │ │ ├── utils │ │ │ │ ├── L.java │ │ │ │ ├── PinYinKit.java │ │ │ │ └── StatusBarUtil.java │ │ │ │ ├── activity │ │ │ │ ├── MainActivity.java │ │ │ │ ├── Country2Activity.java │ │ │ │ ├── Country1Activity.java │ │ │ │ ├── Country4Activity.java │ │ │ │ ├── Country3LvActivity.java │ │ │ │ ├── Country3RvActivity.java │ │ │ │ ├── Country5Activity.java │ │ │ │ └── Country6Activity.java │ │ │ │ └── widget │ │ │ │ ├── SideBar.java │ │ │ │ ├── IndexBar.java │ │ │ │ └── WaveSideBar.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── lp │ │ │ └── sidebar_master │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── lp │ │ └── sidebar_master │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── snapshot └── snapshot.gif ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── README.md ├── gradle.properties ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /snapshot/snapshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/snapshot/snapshot.gif -------------------------------------------------------------------------------- /app/libs/pinyin4j-2.5.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/libs/pinyin4j-2.5.0.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SideBar-master 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/yuan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-xxxhdpi/yuan.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPTim/SideBar-master/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Mar 20 14:52:17 GMT+08:00 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #FFFFFF 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_sidebar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/BaseContent.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base; 2 | 3 | 4 | /** 5 | * File descripition: 6 | * 7 | * @author lp 8 | * @date 2018/6/19 9 | */ 10 | 11 | public class BaseContent { 12 | public static String baseUrl = "http://www.baidu.com/"; 13 | //成功状态值 14 | public static int successCode = 0; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/presenter/CountryView.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.presenter; 2 | 3 | 4 | import com.lp.sidebar_master.base.mvp.BaseModel; 5 | import com.lp.sidebar_master.base.mvp.BaseView; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * File descripition: 11 | * 12 | * @author lp 13 | * @date 2018/6/19 14 | */ 15 | 16 | public interface CountryView extends BaseView { 17 | void onInternationalCodeSuccess(BaseModel> o); 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SideBar-master 2 | 3 | ### RecyclerView实现顶部悬浮、字母排序、过滤搜索 4 | 5 | ### 查看具体实现方式简介,移步到 [简书](https://www.jianshu.com/p/615cda6ac98b) 6 | 7 | ### 快照 8 | ![](https://github.com/LPTim/SideBar-master/blob/master/snapshot/snapshot.gif) 9 | 10 | ### 背景 11 | 在实际开发中避免不了字母排序,过滤搜索等问题,闲暇时对此做了个demo,希望对大家有所帮助,本demo分别用ListView,RecyclerView各实现了一版本,所以大家可以因情况随便使用 12 | ### 功能点简单说明 13 | - 汉字转拼音,按拼音排序 14 | - 字母显示一次 15 | - 顶部字母悬停效果,上滑动画效果实现 16 | - 侧滑字母栏索引跳转到指定字母 17 | - 搜索框字母、数字等多条件搜索 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/api/Fields.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.api; 2 | 3 | /** 4 | * File descripition: 类型标识 统一使用 5 | * 6 | * @author lp 7 | * @date 2018/6/21 8 | */ 9 | 10 | public interface Fields { 11 | 12 | String EIELD_TYPE = "app_type"; 13 | 14 | String EIELD_MESSAGE = "app_message"; 15 | 16 | String EIELD_NEWS_ID = "app_newsId"; 17 | 18 | String EIELD_FATHER_ID = "app_object_message"; 19 | 20 | String EIELD_FROM = "app_come_from"; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/test/java/com/lp/sidebar_master/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master; 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 | } -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/mvp/BaseView.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.mvp; 2 | 3 | /** 4 | * File descripition: 5 | * 6 | * @author lp 7 | * @date 2018/6/19 8 | */ 9 | 10 | public interface BaseView { 11 | /** 12 | * 显示dialog 13 | */ 14 | void showLoading(); 15 | 16 | /** 17 | * 隐藏 dialog 18 | */ 19 | 20 | void hideLoading(); 21 | 22 | /** 23 | * 显示错误信息 24 | * 25 | * @param msg 26 | */ 27 | void showError(String msg); 28 | 29 | /** 30 | * 错误码 31 | */ 32 | void onErrorCode(BaseModel model); 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_search_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | 12 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lp/sidebar_master/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.lp.sidebar_master", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/api/ApiServer.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.api; 2 | 3 | import com.lp.sidebar_master.base.mvp.BaseModel; 4 | import com.lp.sidebar_master.presenter.CountryBean; 5 | 6 | import java.util.List; 7 | 8 | import io.reactivex.Observable; 9 | import retrofit2.http.Field; 10 | import retrofit2.http.FormUrlEncoded; 11 | import retrofit2.http.POST; 12 | 13 | /** 14 | * File descripition: 接口地址之后可能统一为一个 统一的时候头部把另一个地址删除掉 这里没有做分头处理 15 | * 16 | * @author lp 17 | * @date 2018/6/19 18 | */ 19 | 20 | public interface ApiServer { 21 | /** 22 | * 用户注册时获取国际码 23 | * 24 | * @return 25 | */ 26 | @FormUrlEncoded 27 | @POST("abcdefg") 28 | Observable>> InternationalCode(@Field("requestType") String requestType, 29 | @Field("lang") String lang); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 19 | 24 | j 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_country3.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 15 | 16 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_country32.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 16 | 17 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/presenter/CountryPresenter.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.presenter; 2 | 3 | 4 | import com.lp.sidebar_master.base.mvp.BaseModel; 5 | import com.lp.sidebar_master.base.mvp.BaseObserver; 6 | import com.lp.sidebar_master.base.mvp.BasePresenter; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * File descripition: 注册 12 | * 13 | * @author lp 14 | * @date 2018/6/19 15 | */ 16 | 17 | public class CountryPresenter extends BasePresenter { 18 | public CountryPresenter(CountryView baseView) { 19 | super(baseView); 20 | } 21 | 22 | /** 23 | * 用户注册时获取国际码 24 | */ 25 | public void internationalCode() { 26 | addDisposable(apiServer.InternationalCode("Android", "zh"), new BaseObserver(baseView) { 27 | @Override 28 | public void onSuccess(Object o) { 29 | baseView.onInternationalCodeSuccess((BaseModel>) o); 30 | } 31 | 32 | @Override 33 | public void onError(String msg) { 34 | if (baseView != null) { 35 | baseView.showError(msg); 36 | } 37 | } 38 | }); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_country1.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 25 | 26 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/mvp/BaseModel.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.mvp; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * File descripition: mode基类 7 | * 8 | * @author lp 9 | * @date 2018/6/19 10 | */ 11 | 12 | public class BaseModel implements Serializable { 13 | private String message; 14 | private int code; 15 | private T result; 16 | 17 | public BaseModel(String message, int code) { 18 | this.message = message; 19 | this.code = code; 20 | } 21 | 22 | public int getErrcode() { 23 | return code; 24 | } 25 | 26 | public void setErrcode(int code) { 27 | this.code = code; 28 | } 29 | 30 | public String getErrmsg() { 31 | return message; 32 | } 33 | 34 | public void setErrmsg(String message) { 35 | this.message = message; 36 | } 37 | 38 | 39 | public T getData() { 40 | return result; 41 | } 42 | 43 | public void setData(T result) { 44 | this.result = result; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "BaseModel{" + 50 | "code=" + code + 51 | ", msg='" + message + '\'' + 52 | ", result=" + result + 53 | '}'; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_country4.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 25 | 26 | 27 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/adapter/CountryLvAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.adapter; 2 | 3 | import android.content.Context; 4 | 5 | import com.lp.sidebar_master.R; 6 | import com.lp.sidebar_master.base.viewholder.CommonAdapter; 7 | import com.lp.sidebar_master.base.viewholder.ViewHolder; 8 | import com.lp.sidebar_master.presenter.CountryBean; 9 | 10 | import java.util.List; 11 | 12 | 13 | /** 14 | * 俩种adapter封装框架实现 供演示 15 | * File descripition: 选择国家 16 | * 17 | * @author lp 18 | * @date 2018/8/4 19 | */ 20 | 21 | public class CountryLvAdapter extends CommonAdapter { 22 | 23 | public CountryLvAdapter(Context context, List datas, int layoutId) { 24 | super(context, datas, layoutId); 25 | } 26 | 27 | @Override 28 | public void convert(ViewHolder holder, CountryBean countryBean) { 29 | holder.setText(R.id.tv_name, countryBean.getName()); 30 | holder.setText(R.id.tv_number, countryBean.getCode()); 31 | if (countryBean.getLetter()) { 32 | holder.setVisible(R.id.tv_letter, true); 33 | holder.setVisible(R.id.view, true); 34 | holder.setText(R.id.tv_letter, countryBean.getSortLetters()); 35 | } else { 36 | holder.setVisible(R.id.tv_letter, false); 37 | holder.setVisible(R.id.view, false); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/presenter/CountryBean.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.presenter; 2 | 3 | /** 4 | * File descripition: 5 | * 6 | * @author lp 7 | * @date 2018/7/13 8 | */ 9 | 10 | public class CountryBean { 11 | 12 | /** 13 | * code : 86 14 | * name : China 15 | */ 16 | private String code; 17 | private String name; 18 | private String sortLetters; 19 | //是否是字母 20 | private Boolean isLetter = false; 21 | 22 | public Boolean getLetter() { 23 | return isLetter; 24 | } 25 | 26 | public void setLetter(Boolean letter) { 27 | isLetter = letter; 28 | } 29 | 30 | public String getSortLetters() { 31 | return sortLetters; 32 | } 33 | 34 | public void setSortLetters(String sortLetters) { 35 | this.sortLetters = sortLetters; 36 | } 37 | 38 | 39 | public String getCode() { 40 | return code; 41 | } 42 | 43 | public void setCode(String code) { 44 | this.code = code; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "CountryBean{" + 58 | ", code='" + code + '\'' + 59 | ", name='" + name + '\'' + 60 | '}'; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_country2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 26 | 27 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/adapter/CountryRvAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.adapter; 2 | 3 | import android.support.annotation.Nullable; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.chad.library.adapter.base.BaseQuickAdapter; 8 | import com.chad.library.adapter.base.BaseViewHolder; 9 | import com.lp.sidebar_master.R; 10 | import com.lp.sidebar_master.presenter.CountryBean; 11 | 12 | import java.util.List; 13 | 14 | 15 | /** 16 | * 俩种adapter封装框架实现 供演示 17 | * File descripition: 选择国家 18 | * 19 | * @author lp 20 | * @date 2018/8/4 21 | */ 22 | 23 | public class CountryRvAdapter extends BaseQuickAdapter { 24 | 25 | public CountryRvAdapter(int layoutResId, @Nullable List data) { 26 | super(layoutResId, data); 27 | } 28 | 29 | 30 | @Override 31 | protected void convert(BaseViewHolder holder, CountryBean countryBean) { 32 | holder.setText(R.id.tv_name, countryBean.getName()); 33 | holder.setText(R.id.tv_number, countryBean.getCode()); 34 | TextView tv_letter = holder.getView(R.id.tv_letter); 35 | View view = holder.getView(R.id.view); 36 | if (countryBean.getLetter()) { 37 | tv_letter.setVisibility(View.VISIBLE); 38 | view.setVisibility(View.VISIBLE); 39 | holder.setText(R.id.tv_letter, countryBean.getSortLetters()); 40 | } else { 41 | tv_letter.setVisibility(View.GONE); 42 | view.setVisibility(View.GONE); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_country5.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 19 | 20 | 24 | 25 | 28 | 29 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "com.lp.sidebar_master" 7 | minSdkVersion 16 8 | targetSdkVersion 27 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(dir: 'libs', include: ['*.jar']) 23 | implementation 'com.android.support:appcompat-v7:27.1.1' 24 | implementation "com.android.support:design:27.1.1" 25 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 26 | testImplementation 'junit:junit:4.12' 27 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 28 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 29 | //butterknife 30 | compile 'com.jakewharton:butterknife:8.8.1' 31 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' 32 | //网络请求 33 | compile 'com.squareup.okhttp3:okhttp:3.11.0' 34 | compile 'com.squareup.retrofit2:retrofit:2.4.0' 35 | compile 'io.reactivex.rxjava2:rxandroid:2.0.2' 36 | //ConverterFactory的Gson依赖包 37 | compile 'com.squareup.retrofit2:converter-gson:2.4.0' 38 | //CallAdapterFactory的Rx依赖包 39 | compile 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' 40 | //recycleView 适配器 41 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.34' 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/mvp/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.mvp; 2 | 3 | 4 | 5 | 6 | import com.lp.sidebar_master.base.api.ApiRetrofit; 7 | import com.lp.sidebar_master.base.api.ApiServer; 8 | 9 | import io.reactivex.Observable; 10 | import io.reactivex.android.schedulers.AndroidSchedulers; 11 | import io.reactivex.disposables.CompositeDisposable; 12 | import io.reactivex.schedulers.Schedulers; 13 | 14 | /** 15 | * File descripition: 16 | * 17 | * @author lp 18 | * @date 2018/6/19 19 | */ 20 | 21 | public class BasePresenter { 22 | 23 | private CompositeDisposable compositeDisposable; 24 | 25 | 26 | public V baseView; 27 | 28 | protected ApiServer apiServer = ApiRetrofit.getInstance().getApiService(); 29 | 30 | public BasePresenter(V baseView) { 31 | 32 | this.baseView = baseView; 33 | } 34 | 35 | /** 36 | * 解除绑定 37 | */ 38 | public void detachView() { 39 | baseView = null; 40 | removeDisposable(); 41 | } 42 | 43 | /** 44 | * 返回 view 45 | * 46 | * @return 47 | */ 48 | public V getBaseView() { 49 | return baseView; 50 | } 51 | 52 | 53 | public void addDisposable(Observable observable, BaseObserver observer) { 54 | if (compositeDisposable == null) { 55 | compositeDisposable = new CompositeDisposable(); 56 | } 57 | compositeDisposable.add(observable.subscribeOn(Schedulers.io()) 58 | .observeOn(AndroidSchedulers.mainThread()) 59 | .subscribeWith(observer)); 60 | 61 | 62 | } 63 | 64 | public void removeDisposable() { 65 | if (compositeDisposable != null) { 66 | compositeDisposable.dispose(); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/utils/L.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.utils; 2 | 3 | import android.util.Log; 4 | 5 | 6 | /** 7 | * @ Author: qiyue (ustory) 8 | * @ Email: qiyuekoon@foxmail.com 9 | * @ Data:2016/3/6 10 | */ 11 | public class L { 12 | 13 | private final static String TAG = "test"; 14 | /** 15 | * 手动开关 16 | */ 17 | private final static boolean DEBUG = true; 18 | /** 19 | * 跟随线上线下自动开关 20 | */ 21 | // private final static boolean DEBUG = Constant.DEBUG; 22 | private final static boolean CANCEL_TAG = false; 23 | 24 | public static void i(String message) { 25 | if (DEBUG) { 26 | Log.i(TAG, message); 27 | } 28 | } 29 | 30 | public static void i(String tag, String message) { 31 | if (DEBUG) { 32 | if (!CANCEL_TAG) { 33 | Log.i(tag, message); 34 | } else { 35 | i(message); 36 | } 37 | } 38 | } 39 | 40 | public static void w(String message) { 41 | if (DEBUG) { 42 | Log.w(TAG, message); 43 | } 44 | } 45 | 46 | public static void w(String tag, String message) { 47 | if (DEBUG) { 48 | if (!CANCEL_TAG) { 49 | Log.w(tag, message); 50 | } else { 51 | w(message); 52 | } 53 | } 54 | 55 | } 56 | 57 | public static void e(String message) { 58 | if (DEBUG) { 59 | Log.e(TAG, message); 60 | } 61 | } 62 | 63 | public static void e(String tag, String message) { 64 | if (DEBUG) { 65 | if (!CANCEL_TAG) { 66 | Log.e(tag, message); 67 | } else { 68 | e(message); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 27 | 30 | 33 | 36 | 40 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/viewholder/CommonAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.viewholder; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * adapter基类 13 | * 14 | * @param 15 | */ 16 | public abstract class CommonAdapter extends BaseAdapter { 17 | protected Context mContext; 18 | protected List mDatas; 19 | protected LayoutInflater mInflater; 20 | private int layoutId; 21 | private int displayCount; 22 | 23 | public CommonAdapter(Context context, List datas) { 24 | this.mContext = context; 25 | this.mDatas = datas; 26 | mInflater = LayoutInflater.from(context); 27 | } 28 | public CommonAdapter(Context context, List datas, int layoutId) { 29 | this.mContext = context; 30 | this.mDatas = datas; 31 | this.layoutId = layoutId; 32 | mInflater = LayoutInflater.from(context); 33 | } 34 | 35 | @Override 36 | public int getCount() { 37 | if (displayCount != 0) { 38 | return this.displayCount; 39 | } 40 | return mDatas.size(); 41 | } 42 | 43 | public void setDisplayCount(int displayCount) { 44 | this.displayCount = displayCount; 45 | } 46 | 47 | @Override 48 | public T getItem(int position) { 49 | return mDatas.get(position); 50 | } 51 | 52 | @Override 53 | public long getItemId(int position) { 54 | return position; 55 | } 56 | 57 | @Override 58 | public View getView(int position, View convertView, ViewGroup parent) { 59 | ViewHolder holder = ViewHolder.get(mContext, convertView, parent, 60 | layoutId, position); 61 | convert(holder, getItem(position)); 62 | return holder.getConvertView(); 63 | } 64 | 65 | public List getDatas() { 66 | return mDatas; 67 | } 68 | 69 | public void setDatas(List datas) { 70 | mDatas = datas; 71 | } 72 | 73 | public abstract void convert(ViewHolder holder, T t); 74 | 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_country.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 25 | 26 | 30 | 31 | 41 | 42 | 53 | 54 | 55 | 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.lp.sidebar_master.R; 8 | import com.lp.sidebar_master.base.BaseActivity; 9 | import com.lp.sidebar_master.base.mvp.BasePresenter; 10 | 11 | import butterknife.BindView; 12 | import butterknife.ButterKnife; 13 | import butterknife.OnClick; 14 | 15 | /** 16 | * File descripition: 17 | * 18 | * @author lp 19 | * @date 2019/3/20 20 | */ 21 | 22 | public class MainActivity extends BaseActivity { 23 | @BindView(R.id.tv_01) 24 | TextView mTv01; 25 | @BindView(R.id.tv_02) 26 | TextView mTv02; 27 | 28 | @Override 29 | protected BasePresenter createPresenter() { 30 | return null; 31 | } 32 | 33 | @Override 34 | protected int getLayoutId() { 35 | return R.layout.activity_main; 36 | } 37 | 38 | @Override 39 | protected void initData() { 40 | } 41 | 42 | @Override 43 | protected void onCreate(Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | // TODO: add setContentView(...) invocation 46 | ButterKnife.bind(this); 47 | } 48 | 49 | @OnClick({R.id.tv_01, R.id.tv_02, R.id.tv_03, R.id.tv_032, R.id.tv_04, R.id.tv_05, R.id.tv_06}) 50 | public void onViewClicked(View view) { 51 | switch (view.getId()) { 52 | case R.id.tv_01: 53 | startActivity(Country1Activity.class); 54 | break; 55 | case R.id.tv_02: 56 | startActivity(Country2Activity.class); 57 | break; 58 | case R.id.tv_03: 59 | startActivity(Country3RvActivity.class); 60 | break; 61 | case R.id.tv_032: 62 | startActivity(Country3LvActivity.class); 63 | break; 64 | case R.id.tv_04: 65 | startActivity(Country4Activity.class); 66 | break; 67 | case R.id.tv_05: 68 | startActivity(Country5Activity.class); 69 | break; 70 | case R.id.tv_06: 71 | startActivity(Country6Activity.class); 72 | break; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.KeyEvent; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.widget.EditText; 11 | import android.widget.LinearLayout; 12 | import android.widget.RelativeLayout; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | import com.lp.sidebar_master.base.mvp.BaseModel; 17 | import com.lp.sidebar_master.base.mvp.BasePresenter; 18 | import com.lp.sidebar_master.base.mvp.BaseView; 19 | 20 | import butterknife.ButterKnife; 21 | 22 | 23 | /** 24 | * File descripition: activity基类 25 | *

26 | * 27 | * @author lp 28 | * @date 2018/5/16 29 | */ 30 | public abstract class BaseActivity

extends AppCompatActivity implements BaseView { 31 | public Activity mContext; 32 | protected P mPresenter; 33 | 34 | protected abstract P createPresenter(); 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | mContext = this; 40 | setContentView(getLayoutId()); 41 | mPresenter = createPresenter(); 42 | ButterKnife.bind(this); 43 | this.initData(); 44 | } 45 | 46 | /** 47 | * 获取布局ID 48 | * 49 | * @return 50 | */ 51 | protected abstract int getLayoutId(); 52 | 53 | /** 54 | * 数据初始化操作 55 | */ 56 | protected abstract void initData(); 57 | 58 | 59 | @Override 60 | public void showError(String msg) { 61 | } 62 | 63 | @Override 64 | public void onErrorCode(BaseModel model) { 65 | } 66 | 67 | @Override 68 | public void showLoading() { 69 | } 70 | 71 | @Override 72 | public void hideLoading() { 73 | } 74 | 75 | @Override 76 | protected void onDestroy() { 77 | super.onDestroy(); 78 | ButterKnife.bind(this).unbind(); 79 | if (mPresenter != null) { 80 | mPresenter.detachView(); 81 | } 82 | } 83 | 84 | /** 85 | * [页面跳转] 86 | * 87 | * @param clz 88 | */ 89 | public void startActivity(Class clz) { 90 | startActivity(clz, null); 91 | } 92 | 93 | 94 | /** 95 | * [携带数据的页面跳转] 96 | * 97 | * @param clz 98 | * @param bundle 99 | */ 100 | public void startActivity(Class clz, Bundle bundle) { 101 | Intent intent = new Intent(); 102 | intent.setClass(this, clz); 103 | if (bundle != null) { 104 | intent.putExtras(bundle); 105 | } 106 | startActivity(intent); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/Country2Activity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.widget.ListView; 4 | import android.widget.TextView; 5 | 6 | import com.lp.sidebar_master.R; 7 | import com.lp.sidebar_master.adapter.CountryLvAdapter; 8 | import com.lp.sidebar_master.base.BaseActivity; 9 | import com.lp.sidebar_master.base.mvp.BaseModel; 10 | import com.lp.sidebar_master.presenter.CountryBean; 11 | import com.lp.sidebar_master.presenter.CountryPresenter; 12 | import com.lp.sidebar_master.presenter.CountryView; 13 | import com.lp.sidebar_master.utils.PinYinKit; 14 | import com.lp.sidebar_master.widget.WaveSideBar; 15 | 16 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import butterknife.BindView; 22 | 23 | 24 | /** 25 | * File descripition: 侧滑栏拼音全部显示,有动态效果 26 | * 27 | * @author lp 28 | * @date 2018/8/4 29 | */ 30 | 31 | public class Country2Activity extends BaseActivity implements CountryView, WaveSideBar.OnSelectIndexItemListener { 32 | @BindView(R.id.listView) 33 | ListView mListView; 34 | @BindView(R.id.sidebar) 35 | WaveSideBar mSidebar; 36 | @BindView(R.id.tv_word) 37 | TextView mTvWord; 38 | 39 | private CountryLvAdapter mAdapter; 40 | private ArrayList mCountryList; 41 | 42 | @Override 43 | protected CountryPresenter createPresenter() { 44 | return new CountryPresenter(this); 45 | } 46 | 47 | @Override 48 | protected int getLayoutId() { 49 | return R.layout.activity_country2; 50 | } 51 | 52 | 53 | @Override 54 | protected void initData() { 55 | mSidebar.setOnSelectIndexItemListener(this); 56 | 57 | mCountryList = new ArrayList<>(); 58 | mAdapter = new CountryLvAdapter(this, mCountryList, R.layout.item_country); 59 | mListView.setAdapter(mAdapter); 60 | 61 | mPresenter.internationalCode(); 62 | } 63 | 64 | 65 | @Override 66 | public void onInternationalCodeSuccess(BaseModel> o) { 67 | try { 68 | mCountryList.clear(); 69 | mCountryList.addAll(PinYinKit.filledData(o.getData())); 70 | mAdapter.notifyDataSetChanged(); 71 | } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) { 72 | badHanyuPinyinOutputFormatCombination.printStackTrace(); 73 | } 74 | } 75 | 76 | 77 | @Override 78 | public void onSelectIndexItem(String str) { 79 | try { 80 | int position = PinYinKit.getPositionForSection(mCountryList, str.charAt(0)); 81 | if (position != -1) { 82 | mListView.setSelection(position); 83 | } 84 | } catch (Exception e) { 85 | e.printStackTrace(); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/Country1Activity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.widget.ListView; 4 | import android.widget.TextView; 5 | 6 | import com.lp.sidebar_master.R; 7 | import com.lp.sidebar_master.adapter.CountryLvAdapter; 8 | import com.lp.sidebar_master.base.BaseActivity; 9 | import com.lp.sidebar_master.base.mvp.BaseModel; 10 | import com.lp.sidebar_master.presenter.CountryBean; 11 | import com.lp.sidebar_master.presenter.CountryPresenter; 12 | import com.lp.sidebar_master.presenter.CountryView; 13 | import com.lp.sidebar_master.utils.PinYinKit; 14 | import com.lp.sidebar_master.widget.SideBar; 15 | 16 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import butterknife.BindView; 22 | 23 | 24 | /** 25 | * File descripition:侧滑栏拼音全部显示 26 | * 27 | * @author lp 28 | * @date 2018/8/4 29 | */ 30 | 31 | public class Country1Activity extends BaseActivity implements CountryView, SideBar.OnTouchingLetterChangedListener { 32 | @BindView(R.id.listView) 33 | ListView mListView; 34 | @BindView(R.id.sidebar) 35 | SideBar mSidebar; 36 | @BindView(R.id.tv_word) 37 | TextView mTvWord; 38 | 39 | private CountryLvAdapter mAdapter; 40 | private ArrayList mCountryList; 41 | 42 | @Override 43 | protected CountryPresenter createPresenter() { 44 | return new CountryPresenter(this); 45 | } 46 | 47 | @Override 48 | protected int getLayoutId() { 49 | return R.layout.activity_country1; 50 | } 51 | 52 | 53 | @Override 54 | protected void initData() { 55 | mSidebar.setOnTouchingLetterChangedListener(this); 56 | mSidebar.setmTextDialog(mTvWord); 57 | 58 | mCountryList = new ArrayList<>(); 59 | mAdapter = new CountryLvAdapter(this, mCountryList, R.layout.item_country); 60 | mListView.setAdapter(mAdapter); 61 | 62 | mPresenter.internationalCode(); 63 | } 64 | 65 | @Override 66 | public void onInternationalCodeSuccess(BaseModel> o) { 67 | try { 68 | mCountryList.clear(); 69 | mCountryList.addAll(PinYinKit.filledData(o.getData())); 70 | mAdapter.notifyDataSetChanged(); 71 | } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) { 72 | badHanyuPinyinOutputFormatCombination.printStackTrace(); 73 | } 74 | } 75 | 76 | @Override 77 | public void onTouchingLetterChanged(String str) { 78 | try { 79 | int position = PinYinKit.getPositionForSection(mCountryList, str.charAt(0)); 80 | if (position != -1) { 81 | mListView.setSelection(position); 82 | } 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 26 | 27 | 37 | 38 | 48 | 49 | 59 | 60 | 70 | 71 | 81 | 82 | 92 | 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/Country4Activity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.widget.ListView; 4 | import android.widget.TextView; 5 | 6 | import com.lp.sidebar_master.R; 7 | import com.lp.sidebar_master.adapter.CountryLvAdapter; 8 | import com.lp.sidebar_master.base.BaseActivity; 9 | import com.lp.sidebar_master.base.mvp.BaseModel; 10 | import com.lp.sidebar_master.presenter.CountryBean; 11 | import com.lp.sidebar_master.presenter.CountryPresenter; 12 | import com.lp.sidebar_master.presenter.CountryView; 13 | import com.lp.sidebar_master.utils.PinYinKit; 14 | import com.lp.sidebar_master.widget.IndexBar; 15 | 16 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 17 | 18 | import java.util.ArrayList; 19 | import java.util.LinkedHashSet; 20 | import java.util.List; 21 | 22 | import butterknife.BindView; 23 | 24 | 25 | /** 26 | * File descripition: 侧滑栏拼音部分显示,有拼音显示,没有不显示 27 | * 28 | * @author lp 29 | * @date 2018/8/4 30 | */ 31 | 32 | public class Country4Activity extends BaseActivity implements CountryView, IndexBar.OnIndexChangedListener { 33 | @BindView(R.id.listView) 34 | ListView mListView; 35 | @BindView(R.id.sidebar) 36 | IndexBar mSidebar; 37 | @BindView(R.id.tv_word) 38 | TextView mTvWord; 39 | 40 | private CountryLvAdapter mAdapter; 41 | private ArrayList mCountryList; 42 | 43 | //字母集合 44 | private List mLetter = new ArrayList<>(); 45 | 46 | @Override 47 | protected CountryPresenter createPresenter() { 48 | return new CountryPresenter(this); 49 | } 50 | 51 | @Override 52 | protected int getLayoutId() { 53 | return R.layout.activity_country4; 54 | } 55 | 56 | 57 | @Override 58 | protected void initData() { 59 | mSidebar.setOnIndexChangedListener(this); 60 | mSidebar.setSelectedIndexTextView(mTvWord); 61 | 62 | mCountryList = new ArrayList<>(); 63 | mAdapter = new CountryLvAdapter(this, mCountryList, R.layout.item_country); 64 | mListView.setAdapter(mAdapter); 65 | 66 | mPresenter.internationalCode(); 67 | } 68 | 69 | 70 | @Override 71 | public void onInternationalCodeSuccess(BaseModel> o) { 72 | try { 73 | mCountryList.clear(); 74 | mCountryList.addAll(PinYinKit.filledData(o.getData())); 75 | 76 | mLetter.clear(); 77 | for (int i = 0; i < mCountryList.size(); i++) { 78 | mLetter.add(mCountryList.get(i).getSortLetters()); 79 | } 80 | removeDuplicate(mLetter); 81 | String[] letters = mLetter.toArray(new String[mLetter.size()]); 82 | mSidebar.setIndexs(letters); 83 | 84 | mAdapter.notifyDataSetChanged(); 85 | } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) { 86 | badHanyuPinyinOutputFormatCombination.printStackTrace(); 87 | } 88 | } 89 | 90 | 91 | private static void removeDuplicate(List list) { 92 | LinkedHashSet set = new LinkedHashSet(list.size()); 93 | set.addAll(list); 94 | list.clear(); 95 | list.addAll(set); 96 | } 97 | 98 | @Override 99 | public void onIndexChanged(String str) { 100 | try { 101 | int position = PinYinKit.getPositionForSection(mCountryList, str.charAt(0)); 102 | if (position != -1) { 103 | mListView.setSelection(position); 104 | } 105 | } catch (Exception e) { 106 | e.printStackTrace(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/utils/PinYinKit.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.lp.sidebar_master.presenter.CountryBean; 6 | 7 | import net.sourceforge.pinyin4j.PinyinHelper; 8 | import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; 9 | import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; 10 | import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; 11 | import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; 12 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 13 | 14 | import java.util.Collections; 15 | import java.util.Comparator; 16 | import java.util.List; 17 | 18 | /** 19 | * 拼音工具类 20 | */ 21 | public class PinYinKit { 22 | public static String getPingYin(String chineseStr) throws BadHanyuPinyinOutputFormatCombination { 23 | String zhongWenPinYin = ""; 24 | char[] chars = chineseStr.toCharArray(); 25 | 26 | for (int i = 0; i < chars.length; i++) { 27 | String[] pinYin = PinyinHelper.toHanyuPinyinStringArray(chars[i], getDefaultOutputFormat()); 28 | if (pinYin != null) 29 | zhongWenPinYin += pinYin[0]; 30 | else 31 | zhongWenPinYin += chars[i]; 32 | } 33 | return zhongWenPinYin; 34 | } 35 | 36 | private static HanyuPinyinOutputFormat getDefaultOutputFormat() { 37 | HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); 38 | format.setCaseType(HanyuPinyinCaseType.UPPERCASE); 39 | format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); 40 | format.setVCharType(HanyuPinyinVCharType.WITH_U_AND_COLON); 41 | return format; 42 | } 43 | 44 | 45 | //排序 46 | public static List filledData(List mList) throws BadHanyuPinyinOutputFormatCombination { 47 | for (int i = 0; i < mList.size(); i++) { 48 | String pinyin = PinYinKit.getPingYin(mList.get(i).getName()); 49 | String sortString = ""; 50 | if (!TextUtils.isEmpty(pinyin)) { 51 | sortString = pinyin.substring(0, 1).toUpperCase(); 52 | } 53 | if (sortString.matches("[A-Z]")) { 54 | mList.get(i).setSortLetters(sortString.toUpperCase()); 55 | } else { 56 | mList.get(i).setSortLetters("#"); 57 | } 58 | } 59 | //排序 60 | Collections.sort(mList, new PinyinComparatorAdmin()); 61 | initLetter(mList); 62 | return mList; 63 | } 64 | 65 | public static void initLetter(List mList) { 66 | for (int i = 0; i < mList.size(); i++) { 67 | if (i == getPositionForSection(mList, mList.get(i).getSortLetters().charAt(0))) { 68 | mList.get(i).setLetter(true); 69 | } else { 70 | mList.get(i).setLetter(false); 71 | } 72 | } 73 | } 74 | 75 | /** 76 | * 方法含义:将当前字母传入方法体中, 来获取当前字母在集合中第一次出现的位置position 如果等于当前item的position,UI字母栏 77 | * 显示,如果不是,UI字母栏隐藏 78 | * 79 | * @param section 80 | * @return 对应集合中第一个出现的字母 81 | */ 82 | public static int getPositionForSection(List mList, int section) { 83 | for (int i = 0; i < mList.size(); i++) { 84 | String sortStr = mList.get(i).getSortLetters(); 85 | char firstChar = sortStr.toUpperCase().charAt(0); 86 | if (firstChar == section) { 87 | return i; 88 | } 89 | } 90 | return -1; 91 | } 92 | 93 | public static class PinyinComparatorAdmin implements Comparator { 94 | @Override 95 | public int compare(CountryBean o1, CountryBean o2) { 96 | if (o1.getSortLetters().equals("@") || o2.getSortLetters().equals("#")) { 97 | return -1; 98 | } else if (o1.getSortLetters().equals("#") || o2.getSortLetters().equals("@")) { 99 | return 1; 100 | } else { 101 | return o1.getSortLetters().compareTo(o2.getSortLetters()); 102 | } 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/mvp/BaseObserver.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.mvp; 2 | 3 | import com.google.gson.JsonParseException; 4 | import com.lp.sidebar_master.base.BaseContent; 5 | 6 | 7 | import org.json.JSONException; 8 | 9 | import java.io.InterruptedIOException; 10 | import java.net.ConnectException; 11 | import java.net.UnknownHostException; 12 | import java.text.ParseException; 13 | 14 | import io.reactivex.observers.DisposableObserver; 15 | import retrofit2.HttpException; 16 | 17 | /** 18 | * File descripition: 数据处理基类 19 | * 20 | * @author lp 21 | * @date 2018/6/19 22 | */ 23 | 24 | public abstract class BaseObserver extends DisposableObserver { 25 | protected BaseView view; 26 | /** 27 | * 成功状态值 28 | */ 29 | private int successCode = BaseContent.successCode; 30 | /** 31 | * 解析数据失败 32 | */ 33 | public static final int PARSE_ERROR = 1008; 34 | /** 35 | * 网络问题 36 | */ 37 | public static final int BAD_NETWORK = 1007; 38 | /** 39 | * 连接错误 40 | */ 41 | public static final int CONNECT_ERROR = 1006; 42 | /** 43 | * 连接超时 44 | */ 45 | public static final int CONNECT_TIMEOUT = 1005; 46 | /** 47 | * data为null 48 | */ 49 | public static final int CONNECT_NULL = 5555; 50 | 51 | 52 | public BaseObserver(BaseView view) { 53 | this.view = view; 54 | } 55 | 56 | @Override 57 | protected void onStart() { 58 | if (view != null) { 59 | view.showLoading(); 60 | } 61 | } 62 | 63 | @Override 64 | public void onNext(T o) { 65 | try { 66 | if (view != null) { 67 | view.hideLoading(); 68 | } 69 | BaseModel model = (BaseModel) o; 70 | if (model.getData() != null) { 71 | if (model.getErrcode() == successCode) { 72 | onSuccess(o); 73 | } else { 74 | if (view != null) { 75 | view.onErrorCode(model); 76 | onException(model.getErrcode(), model.getErrmsg()); 77 | } 78 | } 79 | } else { 80 | if (view != null) { 81 | view.onErrorCode(model); 82 | onException(CONNECT_NULL,""); 83 | } 84 | } 85 | } catch (Exception e) { 86 | e.printStackTrace(); 87 | onError(e.toString()); 88 | } 89 | } 90 | 91 | @Override 92 | public void onError(Throwable e) { 93 | if (view != null) { 94 | view.hideLoading(); 95 | } 96 | if (e instanceof HttpException) { 97 | // HTTP错误 98 | onException(BAD_NETWORK, ""); 99 | } else if (e instanceof ConnectException 100 | || e instanceof UnknownHostException) { 101 | // 连接错误 102 | onException(CONNECT_ERROR, ""); 103 | } else if (e instanceof InterruptedIOException) { 104 | // 连接超时 105 | onException(CONNECT_TIMEOUT, ""); 106 | } else if (e instanceof JsonParseException 107 | || e instanceof JSONException 108 | || e instanceof ParseException) { 109 | // 解析错误 110 | onException(PARSE_ERROR, ""); 111 | e.printStackTrace(); 112 | } else { 113 | if (e != null) { 114 | onError(e.toString()); 115 | } 116 | } 117 | } 118 | 119 | private void onException(int unknownError, String message) { 120 | switch (unknownError) { 121 | case CONNECT_ERROR: 122 | onError("连接错误"); 123 | break; 124 | case CONNECT_TIMEOUT: 125 | onError("连接超时"); 126 | break; 127 | case BAD_NETWORK: 128 | onError("网络超时"); 129 | break; 130 | //数据为空,显示异常 131 | case CONNECT_NULL: 132 | onError("数据为空,显示异常"); 133 | break; 134 | //解析失败 135 | case PARSE_ERROR: 136 | onError("数据解析失败"); 137 | break; 138 | //其他code值 139 | default: 140 | onError(message); 141 | break; 142 | } 143 | } 144 | 145 | //消失写到这 有一定的延迟 对dialog显示有影响 146 | @Override 147 | public void onComplete() { 148 | /* if (view != null) { 149 | view.hideLoading(); 150 | }*/ 151 | } 152 | 153 | public abstract void onSuccess(T o); 154 | 155 | public abstract void onError(String msg); 156 | } 157 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/Country3LvActivity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.view.View; 4 | import android.view.ViewTreeObserver; 5 | import android.widget.AbsListView; 6 | import android.widget.LinearLayout; 7 | import android.widget.ListView; 8 | import android.widget.TextView; 9 | 10 | import com.lp.sidebar_master.R; 11 | import com.lp.sidebar_master.adapter.CountryLvAdapter; 12 | import com.lp.sidebar_master.base.BaseActivity; 13 | import com.lp.sidebar_master.base.mvp.BaseModel; 14 | import com.lp.sidebar_master.presenter.CountryBean; 15 | import com.lp.sidebar_master.presenter.CountryPresenter; 16 | import com.lp.sidebar_master.presenter.CountryView; 17 | import com.lp.sidebar_master.utils.PinYinKit; 18 | import com.lp.sidebar_master.widget.WaveSideBar; 19 | 20 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | import butterknife.BindView; 26 | 27 | 28 | /** 29 | * File descripition: 侧滑栏拼音全部显示,有动态效果,拼音字母顶部停留 30 | * 31 | * @author lp 32 | * @date 2018/8/4 33 | */ 34 | 35 | public class Country3LvActivity extends BaseActivity implements CountryView, WaveSideBar.OnSelectIndexItemListener { 36 | @BindView(R.id.sidebar) 37 | WaveSideBar mSidebar; 38 | @BindView(R.id.recyclerView) 39 | ListView mRecyclerView; 40 | @BindView(R.id.tv_index) 41 | TextView mTvIndex; 42 | @BindView(R.id.ll_index) 43 | LinearLayout mLlIndex; 44 | 45 | private CountryLvAdapter mAdapter; 46 | private ArrayList mCountryList; 47 | 48 | private int mFlowHeight = 0; 49 | 50 | @Override 51 | protected CountryPresenter createPresenter() { 52 | return new CountryPresenter(this); 53 | } 54 | 55 | @Override 56 | protected int getLayoutId() { 57 | return R.layout.activity_country32; 58 | } 59 | 60 | 61 | @Override 62 | protected void initData() { 63 | mSidebar.setOnSelectIndexItemListener(this); 64 | 65 | mCountryList = new ArrayList<>(); 66 | mAdapter = new CountryLvAdapter(this, mCountryList, R.layout.item_country); 67 | mRecyclerView.setAdapter(mAdapter); 68 | 69 | 70 | /** 71 | * 获取顶部布局的高度 listview的OnScrollListener 回调onScrollStateChanged方法是手势松开后回调 故这个高度进入页面就需要获取 72 | */ 73 | mLlIndex.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 74 | 75 | @Override 76 | public void onGlobalLayout() { 77 | mFlowHeight = mLlIndex.getHeight(); 78 | mLlIndex.getViewTreeObserver().removeGlobalOnLayoutListener(this); 79 | mRecyclerView.setOnScrollListener(new mScrollListener()); 80 | } 81 | }); 82 | 83 | mPresenter.internationalCode(); 84 | } 85 | 86 | 87 | @Override 88 | public void onInternationalCodeSuccess(BaseModel> o) { 89 | try { 90 | mCountryList.clear(); 91 | mCountryList.addAll(PinYinKit.filledData(o.getData())); 92 | mAdapter.notifyDataSetChanged(); 93 | } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) { 94 | badHanyuPinyinOutputFormatCombination.printStackTrace(); 95 | } 96 | } 97 | 98 | private class mScrollListener implements AbsListView.OnScrollListener { 99 | 100 | private int mCurrentPosition = -1; 101 | 102 | @Override 103 | public void onScrollStateChanged(AbsListView absListView, int i) { 104 | if (mLlIndex != null || mFlowHeight < 1) { 105 | mFlowHeight = mLlIndex.getMeasuredHeight(); 106 | } 107 | } 108 | 109 | @Override 110 | public void onScroll(AbsListView absListView, int position, int i1, int i2) { 111 | int firstVisibleItemPosition = absListView.getFirstVisiblePosition(); 112 | View view = absListView.getChildAt(position + 1 - absListView.getFirstVisiblePosition()); 113 | 114 | if (view != null) { 115 | if (view.getTop() <= mFlowHeight && mCountryList.get(firstVisibleItemPosition + 1).getLetter()) { 116 | mLlIndex.setY(view.getTop() - mFlowHeight); 117 | } else { 118 | mLlIndex.setY(0); 119 | } 120 | } 121 | 122 | if (mCurrentPosition != firstVisibleItemPosition) { 123 | mCurrentPosition = firstVisibleItemPosition; 124 | if (mCountryList.size() > 0) { 125 | mTvIndex.setText(mCountryList.get(mCurrentPosition).getSortLetters()); 126 | } 127 | } 128 | } 129 | } 130 | 131 | @Override 132 | public void onSelectIndexItem(String str) { 133 | try { 134 | int position = PinYinKit.getPositionForSection(mCountryList, str.charAt(0)); 135 | if (position != -1) { 136 | mRecyclerView.setSelection(position); 137 | } 138 | } catch (Exception e) { 139 | e.printStackTrace(); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/Country3RvActivity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.support.v7.widget.LinearLayoutManager; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.View; 6 | import android.widget.LinearLayout; 7 | import android.widget.TextView; 8 | 9 | import com.lp.sidebar_master.R; 10 | import com.lp.sidebar_master.adapter.CountryRvAdapter; 11 | import com.lp.sidebar_master.base.BaseActivity; 12 | import com.lp.sidebar_master.base.mvp.BaseModel; 13 | import com.lp.sidebar_master.presenter.CountryBean; 14 | import com.lp.sidebar_master.presenter.CountryPresenter; 15 | import com.lp.sidebar_master.presenter.CountryView; 16 | import com.lp.sidebar_master.utils.PinYinKit; 17 | import com.lp.sidebar_master.widget.WaveSideBar; 18 | 19 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import butterknife.BindView; 25 | 26 | 27 | /** 28 | * File descripition: 侧滑栏拼音全部显示,有动态效果,拼音字母顶部停留 29 | * 30 | * @author lp 31 | * @date 2018/8/4 32 | */ 33 | 34 | public class Country3RvActivity extends BaseActivity implements CountryView, WaveSideBar.OnSelectIndexItemListener { 35 | @BindView(R.id.sidebar) 36 | WaveSideBar mSidebar; 37 | @BindView(R.id.recyclerView) 38 | RecyclerView mRecyclerView; 39 | @BindView(R.id.tv_index) 40 | TextView mTvIndex; 41 | @BindView(R.id.ll_index) 42 | LinearLayout mLlIndex; 43 | 44 | private CountryRvAdapter mAdapter; 45 | private ArrayList mCountryList; 46 | 47 | private LinearLayoutManager layoutManager; 48 | 49 | @Override 50 | protected CountryPresenter createPresenter() { 51 | return new CountryPresenter(this); 52 | } 53 | 54 | @Override 55 | protected int getLayoutId() { 56 | return R.layout.activity_country3; 57 | } 58 | 59 | 60 | @Override 61 | protected void initData() { 62 | mSidebar.setOnSelectIndexItemListener(this); 63 | 64 | //创建布局管理 65 | layoutManager = new LinearLayoutManager(mContext); 66 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL); 67 | mRecyclerView.setLayoutManager(layoutManager); 68 | 69 | mCountryList = new ArrayList<>(); 70 | mAdapter = new CountryRvAdapter(R.layout.item_country, mCountryList); 71 | mRecyclerView.setAdapter(mAdapter); 72 | mRecyclerView.addOnScrollListener(new mScrollListener()); 73 | 74 | mPresenter.internationalCode(); 75 | } 76 | 77 | 78 | @Override 79 | public void onInternationalCodeSuccess(BaseModel> o) { 80 | try { 81 | mCountryList.clear(); 82 | mCountryList.addAll(PinYinKit.filledData(o.getData())); 83 | mAdapter.notifyDataSetChanged(); 84 | } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) { 85 | badHanyuPinyinOutputFormatCombination.printStackTrace(); 86 | } 87 | } 88 | 89 | 90 | private class mScrollListener extends RecyclerView.OnScrollListener { 91 | 92 | private int mFlowHeight = 0; 93 | private int mCurrentPosition = -1; 94 | 95 | @Override 96 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 97 | if (mLlIndex != null || mFlowHeight < 1) { 98 | mFlowHeight = mLlIndex.getMeasuredHeight(); 99 | } 100 | } 101 | 102 | @Override 103 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 104 | int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); 105 | View view = layoutManager.findViewByPosition(firstVisibleItemPosition + 1); 106 | 107 | if (view != null) { 108 | if (view.getTop() <= mFlowHeight && mCountryList.get(firstVisibleItemPosition + 1).getLetter()) { 109 | mLlIndex.setY(view.getTop() - mFlowHeight); 110 | } else { 111 | mLlIndex.setY(0); 112 | } 113 | } 114 | 115 | if (mCurrentPosition != firstVisibleItemPosition) { 116 | mCurrentPosition = firstVisibleItemPosition; 117 | if (mCountryList.size() > 0) { 118 | mTvIndex.setText(mCountryList.get(mCurrentPosition).getSortLetters()); 119 | mLlIndex.setVisibility(View.VISIBLE); 120 | } else { 121 | mLlIndex.setVisibility(View.GONE); 122 | } 123 | } 124 | } 125 | } 126 | 127 | @Override 128 | public void onSelectIndexItem(String str) { 129 | try { 130 | int position = PinYinKit.getPositionForSection(mCountryList, str.charAt(0)); 131 | if (position != -1) { 132 | /** 133 | * 直接到指定位置 134 | */ 135 | layoutManager.scrollToPositionWithOffset(position, 0); 136 | layoutManager.setStackFromEnd(true); 137 | /** 138 | * 滚动到指定位置(有滚动效果) 139 | */ 140 | // linearSmoothScroller.setTargetPosition(position); 141 | // layoutManager.startSmoothScroll(linearSmoothScroller); 142 | 143 | } 144 | } catch (Exception e) { 145 | e.printStackTrace(); 146 | } 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/widget/SideBar.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.widget; 2 | import android.content.Context; 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.Typeface; 7 | import android.graphics.drawable.ColorDrawable; 8 | import android.util.AttributeSet; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.widget.TextView; 12 | 13 | import com.lp.sidebar_master.R; 14 | 15 | 16 | /** 17 | * 侧滑拼音 18 | */ 19 | 20 | public class SideBar extends View { 21 | 22 | /** 23 | * 触摸字母索引发生变化的回调接口 24 | */ 25 | private OnTouchingLetterChangedListener onTouchingLetterChangedListener; 26 | /** 27 | * 侧边栏字母显示 28 | */ 29 | public static String[] b = 30 | { 31 | "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", 32 | "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", 33 | "W", "X", "Y", "Z", "#" 34 | }; 35 | /** 36 | * 变量 choose 用来标示当前手指触摸的字母索引在 alphabet 数组中的下标 37 | */ 38 | private int choose = -1; 39 | /** 40 | * 定义画笔 41 | */ 42 | private Paint paint = new Paint(); 43 | /** 44 | * 当手指在 SideBar 上滑动的时候,会有一个 TextView 来显示当前手指触摸的字母索引, 45 | */ 46 | private TextView mTextDialog; 47 | 48 | /** 49 | * 为SideBar设置显示字母的TextView 50 | * 51 | * @param mTextDialog 52 | */ 53 | public void setmTextDialog(TextView mTextDialog) { 54 | this.mTextDialog = mTextDialog; 55 | } 56 | 57 | public SideBar(Context context, AttributeSet attrs, int defStyleAttr) { 58 | super(context, attrs, defStyleAttr); 59 | } 60 | 61 | public SideBar(Context context, AttributeSet attrs) { 62 | super(context, attrs); 63 | } 64 | 65 | public SideBar(Context context) { 66 | super(context); 67 | } 68 | 69 | /** 70 | * 绘制列表控件的方法 71 | * 将要绘制的字母以从上到下的顺序绘制在一个指定区域 72 | * 如果是进行选中的字母就进行高亮显示 73 | */ 74 | @Override 75 | protected void onDraw(Canvas canvas) { 76 | super.onDraw(canvas); 77 | // 获取SideBar的高度 78 | int height = getHeight(); 79 | // 获取SideBar的宽度 80 | int width = getWidth(); 81 | // 获得每个字母索引的高度 82 | int singleHeight = height / b.length; 83 | 84 | //绘制每一个字母的索引 85 | for (int i = 0; i < b.length; i++) { 86 | paint.setColor(Color.rgb(33, 65, 98));//设置字母颜色 87 | paint.setTypeface(Typeface.DEFAULT_BOLD);//设置字体 88 | paint.setAntiAlias(true);//抗锯齿 89 | paint.setTextSize(20);//设置字体大小 90 | 91 | // 如果当前的手指触摸索引和字母索引相同,那么字体颜色进行区分 92 | if (i == choose) { 93 | paint.setColor(Color.parseColor("#3399ff")); 94 | paint.setFakeBoldText(true); 95 | } 96 | 97 | /** 98 | * 绘制字体,需要制定绘制的x、y轴坐标 99 | * x轴坐标 = 控件宽度的一半 - 字体宽度的一半 100 | * y轴坐标 = singleHeight * i + singleHeight 101 | */ 102 | float x = width / 2 - paint.measureText(b[i]) / 2; 103 | float y = singleHeight * i + singleHeight; 104 | canvas.drawText(b[i], x, y, paint); 105 | 106 | // 重置画笔,准备绘制下一个字母索引 107 | paint.reset(); 108 | } 109 | } 110 | 111 | @SuppressWarnings("deprecation") 112 | @Override 113 | public boolean dispatchTouchEvent(MotionEvent event) { 114 | // 触摸事件的代码 115 | final int action = event.getAction(); 116 | //手指触摸点在屏幕的Y坐标 117 | final float y = event.getY(); 118 | // 因为currentChoosenAlphabetIndex会不断发生变化,所以用一个变量存储起来 119 | final int oldChoose = choose; 120 | final OnTouchingLetterChangedListener changedListener = onTouchingLetterChangedListener; 121 | // 比例 = 手指触摸点在屏幕的y轴坐标 / SideBar的高度 122 | // 触摸点的索引 = 比例 * 字母索引数组的长度 123 | final int letterPos = (int) (y / getHeight() * b.length); 124 | 125 | switch (action) { 126 | case MotionEvent.ACTION_UP: 127 | // 如果手指没有触摸屏幕,SideBar的背景颜色为默认,索引字母提示控件不可见 128 | setBackgroundDrawable(new ColorDrawable(0x00000000)); 129 | choose = -1; 130 | invalidate(); 131 | if (mTextDialog != null) { 132 | mTextDialog.setVisibility(View.INVISIBLE); 133 | } 134 | break; 135 | 136 | default: 137 | // 其他情况,比如滑动屏幕、点击屏幕等等,SideBar会改变背景颜色,索引字母提示控件可见,同时需要设置内容 138 | setBackgroundResource(R.drawable.bg_sidebar); 139 | // 不是同一个字母索引 140 | if (oldChoose != letterPos) { 141 | // 如果触摸点没有超出控件范围 142 | if (letterPos >= 0 && letterPos < b.length) { 143 | if (changedListener != null) 144 | changedListener.onTouchingLetterChanged(b[letterPos]); 145 | if (mTextDialog != null) { 146 | mTextDialog.setText(b[letterPos]); 147 | mTextDialog.setVisibility(View.VISIBLE); 148 | } 149 | 150 | choose = letterPos; 151 | invalidate(); 152 | } 153 | } 154 | break; 155 | } 156 | return true; 157 | } 158 | 159 | public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener changedListener) { 160 | this.onTouchingLetterChangedListener = changedListener; 161 | } 162 | 163 | /** 164 | * 当手指触摸的字母索引发生变化时,调用该回调接口 165 | */ 166 | public interface OnTouchingLetterChangedListener { 167 | void onTouchingLetterChanged(String str); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/widget/IndexBar.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.widget; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.Rect; 8 | import android.util.AttributeSet; 9 | import android.util.DisplayMetrics; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.widget.TextView; 13 | 14 | 15 | 16 | /** 17 | * Created by SouthernBox on 2016/10/25 0025. 18 | * 侧边索引栏控件 19 | */ 20 | 21 | public class IndexBar extends View { 22 | 23 | /** 24 | * 索引字母颜色 25 | */ 26 | private static final int LETTER_COLOR = 0xFF2E8BE6; 27 | 28 | /** 29 | * 索引字母数组 30 | */ 31 | public String[] indexs = {}; 32 | 33 | /** 34 | * 控件的宽高 35 | */ 36 | private int mWidth; 37 | private int mHeight; 38 | 39 | /** 40 | * 单元格的高度 41 | */ 42 | private float mCellHeight; 43 | 44 | /** 45 | * 顶部间距 46 | */ 47 | private float mMarginTop; 48 | 49 | private Paint mPaint; 50 | 51 | public IndexBar(Context context) { 52 | super(context); 53 | init(); 54 | } 55 | 56 | public IndexBar(Context context, AttributeSet attrs) { 57 | super(context, attrs); 58 | init(); 59 | } 60 | 61 | private void init() { 62 | mPaint = new Paint(); 63 | mPaint.setColor(LETTER_COLOR); 64 | mPaint.setTextSize(dp2px(getContext(), 12)); 65 | mPaint.setAntiAlias(true); // 去掉锯齿,让字体边缘变得平滑 66 | } 67 | 68 | public void setIndexs(String[] indexs) { 69 | this.indexs = indexs; 70 | mMarginTop = (mHeight - mCellHeight * indexs.length) / 2; 71 | invalidate(); 72 | } 73 | 74 | @Override 75 | protected void onDraw(Canvas canvas) { 76 | //字母的坐标点:(x,y) 77 | if (indexs.length <= 0) { 78 | return; 79 | } 80 | for (int i = 0; i < indexs.length; i++) { 81 | String letter = indexs[i]; 82 | float x = mWidth / 2 - getTextWidth(letter) / 2; 83 | float y = mCellHeight / 2 + getTextHeight(letter) / 2 + mCellHeight * i + mMarginTop; 84 | canvas.drawText(letter, x, y, mPaint); 85 | } 86 | } 87 | 88 | /** 89 | * 获取字符的宽度 90 | * 91 | * @param text 需要测量的字母 92 | * @return 对应字母的高度 93 | */ 94 | public float getTextWidth(String text) { 95 | Rect bounds = new Rect(); 96 | mPaint.getTextBounds(text, 0, text.length(), bounds); 97 | return bounds.width(); 98 | } 99 | 100 | /** 101 | * 获取字符的高度 102 | * 103 | * @param text 需要测量的字母 104 | * @return 对应字母的高度 105 | */ 106 | public float getTextHeight(String text) { 107 | Rect bounds = new Rect(); 108 | mPaint.getTextBounds(text, 0, text.length(), bounds); 109 | return bounds.height(); 110 | } 111 | 112 | 113 | @Override 114 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 115 | super.onSizeChanged(w, h, oldw, oldh); 116 | mWidth = getMeasuredWidth(); 117 | mHeight = getMeasuredHeight(); 118 | mCellHeight = (mHeight * 1f / 27); //26个字母加上“#” 119 | mMarginTop = (mHeight - mCellHeight * indexs.length) / 2; 120 | } 121 | 122 | @Override 123 | @SuppressLint("ClickableViewAccessibility") 124 | public boolean onTouchEvent(MotionEvent event) { 125 | switch (event.getAction()) { 126 | case MotionEvent.ACTION_DOWN: 127 | case MotionEvent.ACTION_MOVE: 128 | // 按下字母的下标 129 | int letterIndex = (int) ((event.getY() - mMarginTop) / mCellHeight); 130 | // 判断是否越界 131 | if (letterIndex >= 0 && letterIndex < indexs.length) { 132 | // 显示按下的字母 133 | if (textView != null) { 134 | textView.setVisibility(View.VISIBLE); 135 | textView.setText(indexs[letterIndex]); 136 | } 137 | //通过回调方法通知列表定位 138 | if (mOnIndexChangedListener != null) { 139 | mOnIndexChangedListener.onIndexChanged(indexs[letterIndex]); 140 | } 141 | } 142 | break; 143 | case MotionEvent.ACTION_UP: 144 | case MotionEvent.ACTION_CANCEL: 145 | if (textView != null) { 146 | textView.setVisibility(View.GONE); 147 | } 148 | break; 149 | } 150 | 151 | return true; 152 | } 153 | 154 | public interface OnIndexChangedListener { 155 | /** 156 | * 按下字母改变了 157 | * 158 | * @param index 按下的字母 159 | */ 160 | void onIndexChanged(String index); 161 | } 162 | 163 | private OnIndexChangedListener mOnIndexChangedListener; 164 | 165 | private TextView textView; 166 | 167 | public void setOnIndexChangedListener(OnIndexChangedListener onIndexChangedListener) { 168 | this.mOnIndexChangedListener = onIndexChangedListener; 169 | } 170 | 171 | /** 172 | * 设置显示按下首字母的TextView 173 | */ 174 | public void setSelectedIndexTextView(TextView textView) { 175 | this.textView = textView; 176 | } 177 | 178 | /** 179 | * 将dp值转换为px值 180 | * 181 | * @param context 上下文 182 | * @param dpValue dp单位的长度 183 | * @return px单位的长度 184 | */ 185 | public static int dp2px(Context context, int dpValue) { 186 | //获取屏幕密度 187 | DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 188 | //屏幕密度的比例值 189 | float density = displayMetrics.density; 190 | //将dp转换为px 191 | return (int) (dpValue * density + 0.5); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/Country5Activity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.support.v4.view.MenuItemCompat; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.support.v7.widget.SearchView; 7 | import android.support.v7.widget.Toolbar; 8 | import android.text.TextUtils; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | 15 | import com.lp.sidebar_master.R; 16 | import com.lp.sidebar_master.adapter.CountryRvAdapter; 17 | import com.lp.sidebar_master.base.BaseActivity; 18 | import com.lp.sidebar_master.base.mvp.BaseModel; 19 | import com.lp.sidebar_master.presenter.CountryBean; 20 | import com.lp.sidebar_master.presenter.CountryPresenter; 21 | import com.lp.sidebar_master.presenter.CountryView; 22 | import com.lp.sidebar_master.utils.PinYinKit; 23 | import com.lp.sidebar_master.utils.StatusBarUtil; 24 | import com.lp.sidebar_master.widget.WaveSideBar; 25 | 26 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 27 | 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | import butterknife.BindView; 32 | 33 | 34 | /** 35 | * File descripition: 侧滑栏拼音全部显示,有动态效果,拼音字母顶部停留,顶部拼音搜索 36 | * 37 | * @author lp 38 | * @date 2018/8/4 39 | */ 40 | 41 | public class Country5Activity extends BaseActivity implements CountryView, WaveSideBar.OnSelectIndexItemListener { 42 | @BindView(R.id.sidebar) 43 | WaveSideBar mSidebar; 44 | @BindView(R.id.recyclerView) 45 | RecyclerView mRecyclerView; 46 | @BindView(R.id.tv_index) 47 | TextView mTvIndex; 48 | @BindView(R.id.ll_index) 49 | LinearLayout mLlIndex; 50 | @BindView(R.id.toolbar) 51 | Toolbar mToolbar; 52 | 53 | private CountryRvAdapter mAdapter; 54 | private ArrayList mCountryList; 55 | private ArrayList mCountryListAll; 56 | private LinearLayoutManager layoutManager; 57 | 58 | @Override 59 | protected CountryPresenter createPresenter() { 60 | return new CountryPresenter(this); 61 | } 62 | 63 | @Override 64 | protected int getLayoutId() { 65 | return R.layout.activity_country5; 66 | } 67 | 68 | 69 | @Override 70 | protected void initData() { 71 | StatusBarUtil.setColor(this, getResources().getColor(R.color.colorPrimary), 0); 72 | 73 | setSupportActionBar(mToolbar); 74 | mSidebar.setOnSelectIndexItemListener(this); 75 | 76 | mCountryList = new ArrayList<>(); 77 | mCountryListAll = new ArrayList<>(); 78 | //创建布局管理 79 | layoutManager = new LinearLayoutManager(mContext); 80 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL); 81 | mRecyclerView.setLayoutManager(layoutManager); 82 | 83 | mAdapter = new CountryRvAdapter(R.layout.item_country, mCountryList); 84 | mRecyclerView.setAdapter(mAdapter); 85 | mRecyclerView.addOnScrollListener(new mScrollListener()); 86 | 87 | mPresenter.internationalCode(); 88 | } 89 | 90 | @Override 91 | public boolean onCreateOptionsMenu(Menu menu) { 92 | getMenuInflater().inflate(R.menu.menu_search_view, menu); 93 | 94 | //找到searchView 95 | MenuItem searchItem = menu.findItem(R.id.action_search); 96 | SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); 97 | 98 | // searchView.setSubmitButtonEnabled(true);//显示提交按钮 99 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 100 | @Override 101 | public boolean onQueryTextSubmit(String query) { 102 | //提交按钮的点击事件 103 | return true; 104 | } 105 | 106 | @Override 107 | public boolean onQueryTextChange(String newText) { 108 | //当输入框内容改变的时候回调 109 | try { 110 | filerData(newText.toString()); 111 | } catch (BadHanyuPinyinOutputFormatCombination e) { 112 | e.printStackTrace(); 113 | } 114 | return true; 115 | } 116 | }); 117 | return super.onCreateOptionsMenu(menu); 118 | } 119 | 120 | 121 | @Override 122 | public void onInternationalCodeSuccess(BaseModel> o) { 123 | try { 124 | mCountryList.clear(); 125 | mCountryListAll.clear(); 126 | mCountryList.addAll(PinYinKit.filledData(o.getData())); 127 | mCountryListAll.addAll(PinYinKit.filledData(o.getData())); 128 | mAdapter.notifyDataSetChanged(); 129 | } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) { 130 | badHanyuPinyinOutputFormatCombination.printStackTrace(); 131 | } 132 | } 133 | 134 | 135 | private class mScrollListener extends RecyclerView.OnScrollListener { 136 | 137 | private int mFlowHeight = 0; 138 | private int mCurrentPosition = -1; 139 | 140 | @Override 141 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 142 | if (mLlIndex != null || mFlowHeight < 1) { 143 | mFlowHeight = mLlIndex.getMeasuredHeight(); 144 | } 145 | } 146 | 147 | @Override 148 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 149 | int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); 150 | View view = layoutManager.findViewByPosition(firstVisibleItemPosition + 1); 151 | 152 | if (view != null) { 153 | if (view.getTop() <= mFlowHeight && mCountryList.get(firstVisibleItemPosition + 1).getLetter()) { 154 | mLlIndex.setY(view.getTop() - mFlowHeight); 155 | } else { 156 | mLlIndex.setY(0); 157 | } 158 | } 159 | 160 | // if (mCurrentPosition != firstVisibleItemPosition) { 161 | mCurrentPosition = firstVisibleItemPosition; 162 | if (mCountryList.size() > 0) { 163 | mTvIndex.setText(mCountryList.get(mCurrentPosition).getSortLetters()); 164 | mLlIndex.setVisibility(View.VISIBLE); 165 | } else { 166 | mLlIndex.setVisibility(View.GONE); 167 | } 168 | // } 169 | } 170 | } 171 | 172 | 173 | @Override 174 | public void onSelectIndexItem(String str) { 175 | try { 176 | int position = PinYinKit.getPositionForSection(mCountryList, str.charAt(0)); 177 | if (position != -1) { 178 | /** 179 | * 直接到指定位置 180 | */ 181 | layoutManager.scrollToPositionWithOffset(position, 0); 182 | // layoutManager.setStackFromEnd(true); 183 | /** 184 | * 滚动到指定位置(有滚动效果) 185 | */ 186 | // LinearSmoothScroller s1 = new TopSmoothScroller(this); 187 | // s1.setTargetPosition(position); 188 | // layoutManager.startSmoothScroll(s1); 189 | } 190 | } catch (Exception e) { 191 | e.printStackTrace(); 192 | } 193 | } 194 | 195 | 196 | private void filerData(String str) throws BadHanyuPinyinOutputFormatCombination { 197 | if (TextUtils.isEmpty(str)) { 198 | mCountryList.clear(); 199 | mCountryList.addAll(mCountryListAll); 200 | } else { 201 | mCountryList.clear(); 202 | for (CountryBean ms : mCountryListAll) { 203 | String name = ms.getName(); 204 | String code = ms.getCode(); 205 | if (name.indexOf(str.toString()) != -1 206 | || PinYinKit.getPingYin(name).startsWith(str.toString()) 207 | || PinYinKit.getPingYin(name).startsWith(str.toUpperCase().toString()) 208 | || name.contains(str) 209 | 210 | || PinYinKit.getPingYin(code).startsWith(str.toString()) 211 | || PinYinKit.getPingYin(code).startsWith(str.toUpperCase().toString()) 212 | || code.contains(str) 213 | ) { 214 | mCountryList.add(ms); 215 | } 216 | } 217 | } 218 | PinYinKit.initLetter(mCountryList); 219 | layoutManager.scrollToPositionWithOffset(0, 0); 220 | mAdapter.notifyDataSetChanged(); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/viewholder/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.viewholder; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Paint; 7 | import android.graphics.Typeface; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Build; 10 | import android.text.util.Linkify; 11 | import android.util.SparseArray; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.animation.AlphaAnimation; 16 | import android.widget.Checkable; 17 | import android.widget.ImageView; 18 | import android.widget.ProgressBar; 19 | import android.widget.RatingBar; 20 | import android.widget.TextView; 21 | 22 | /** 23 | * 以前的做法是这样子的 24 | * viewHolder = new ViewHolder(); 25 | * convertView = layoutInflater.inflate(R.layout.people_list_item, null, false); 26 | * viewHolder.checkBox = (CheckBox)convertView.findViewById(R.id.checkBox); 27 | * viewHolder.name = (TextView)convertView.findViewById(R.id.name); 28 | * 缺点,如果我们换了一个Item,我们就需要在ViewHolder中从新添加对应空间的变量 29 | * 也就需要重写viewHolder, 30 | * 因此这里用了一个通用的方法,就是在viewHolder中用一个类似于map的键值来保存findViewById对象, 31 | * 这种比先前还有一个好处就是,不管多少条Item,Item中的每个控件只会被findViewById一次 32 | * 以前的方法,当前页面缓存的个数4个,然后内存中对每个控件都是对应4个,也就是findViewById4次,如果屏幕较大就会越来越多 33 | * 以后一个项目几十个Adapter一个ViewHolder直接hold住全场 34 | * 35 | * @ Author: qiyue (ustory) 36 | * @ Email: qiyuekoon@foxmail.com 37 | * @ Data:2016/3/6 38 | */ 39 | public class ViewHolder { 40 | private SparseArray mViews; 41 | private int mPosition; 42 | private View mConvertView; 43 | private Context mContext; 44 | private int mLayoutId; 45 | 46 | public ViewHolder(Context context, ViewGroup parent, int layoutId, 47 | int position) { 48 | mContext = context; 49 | mLayoutId = layoutId; 50 | this.mPosition = position; 51 | this.mViews = new SparseArray(); 52 | mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, 53 | false); 54 | mConvertView.setTag(this); 55 | } 56 | 57 | public static ViewHolder get(Context context, View convertView, 58 | ViewGroup parent, int layoutId, int position) { 59 | if (convertView == null) { 60 | return new ViewHolder(context, parent, layoutId, position); 61 | } else { 62 | ViewHolder holder = (ViewHolder) convertView.getTag(); 63 | holder.mPosition = position; 64 | return holder; 65 | } 66 | } 67 | 68 | public int getPosition() { 69 | return mPosition; 70 | } 71 | 72 | public int getLayoutId() { 73 | return mLayoutId; 74 | } 75 | 76 | /** 77 | * 通过viewId获取控件 78 | * 79 | * @param viewId 80 | * @return 81 | */ 82 | public T getView(int viewId) { 83 | View view = mViews.get(viewId); 84 | if (view == null) { 85 | view = mConvertView.findViewById(viewId); 86 | mViews.put(viewId, view); 87 | } 88 | return (T) view; 89 | } 90 | 91 | public View getConvertView() { 92 | return mConvertView; 93 | } 94 | 95 | /** 96 | * 设置TextView的�?? 97 | * 98 | * @param viewId 99 | * @param text 100 | * @return 101 | */ 102 | public ViewHolder setText(int viewId, String text) { 103 | TextView tv = getView(viewId); 104 | tv.setText(text); 105 | return this; 106 | } 107 | 108 | public ViewHolder setImageResource(int viewId, int resId) { 109 | ImageView view = getView(viewId); 110 | view.setImageResource(resId); 111 | return this; 112 | } 113 | 114 | public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) { 115 | ImageView view = getView(viewId); 116 | view.setImageBitmap(bitmap); 117 | return this; 118 | } 119 | 120 | public ViewHolder setImageDrawable(int viewId, Drawable drawable) { 121 | ImageView view = getView(viewId); 122 | view.setImageDrawable(drawable); 123 | return this; 124 | } 125 | 126 | public ViewHolder setBackgroundColor(int viewId, int color) { 127 | View view = getView(viewId); 128 | view.setBackgroundColor(color); 129 | return this; 130 | } 131 | 132 | public ViewHolder setBackgroundRes(int viewId, int backgroundRes) { 133 | View view = getView(viewId); 134 | view.setBackgroundResource(backgroundRes); 135 | return this; 136 | } 137 | 138 | public ViewHolder setTextColor(int viewId, int textColor) { 139 | TextView view = getView(viewId); 140 | view.setTextColor(textColor); 141 | return this; 142 | } 143 | 144 | public ViewHolder setTextColorRes(int viewId, int textColorRes) { 145 | TextView view = getView(viewId); 146 | view.setTextColor(mContext.getResources().getColor(textColorRes)); 147 | return this; 148 | } 149 | 150 | @SuppressLint("NewApi") 151 | public ViewHolder setAlpha(int viewId, float value) { 152 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 153 | getView(viewId).setAlpha(value); 154 | } else { 155 | // Pre-honeycomb hack to set Alpha value 156 | AlphaAnimation alpha = new AlphaAnimation(value, value); 157 | alpha.setDuration(0); 158 | alpha.setFillAfter(true); 159 | getView(viewId).startAnimation(alpha); 160 | } 161 | return this; 162 | } 163 | 164 | public ViewHolder setVisible(int viewId, boolean visible) { 165 | View view = getView(viewId); 166 | view.setVisibility(visible ? View.VISIBLE : View.GONE); 167 | return this; 168 | } 169 | 170 | public ViewHolder linkify(int viewId) { 171 | TextView view = getView(viewId); 172 | Linkify.addLinks(view, Linkify.ALL); 173 | return this; 174 | } 175 | 176 | public ViewHolder setTypeface(Typeface typeface, int... viewIds) { 177 | for (int viewId : viewIds) { 178 | TextView view = getView(viewId); 179 | view.setTypeface(typeface); 180 | view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); 181 | } 182 | return this; 183 | } 184 | 185 | public ViewHolder setProgress(int viewId, int progress) { 186 | ProgressBar view = getView(viewId); 187 | view.setProgress(progress); 188 | return this; 189 | } 190 | 191 | public ViewHolder setProgress(int viewId, int progress, int max) { 192 | ProgressBar view = getView(viewId); 193 | view.setMax(max); 194 | view.setProgress(progress); 195 | return this; 196 | } 197 | 198 | public ViewHolder setMax(int viewId, int max) { 199 | ProgressBar view = getView(viewId); 200 | view.setMax(max); 201 | return this; 202 | } 203 | 204 | public ViewHolder setRating(int viewId, float rating) { 205 | RatingBar view = getView(viewId); 206 | view.setRating(rating); 207 | return this; 208 | } 209 | 210 | public ViewHolder setRating(int viewId, float rating, int max) { 211 | RatingBar view = getView(viewId); 212 | view.setMax(max); 213 | view.setRating(rating); 214 | return this; 215 | } 216 | 217 | public ViewHolder setTag(int viewId, Object tag) { 218 | View view = getView(viewId); 219 | view.setTag(tag); 220 | return this; 221 | } 222 | 223 | public ViewHolder setTag(int viewId, int key, Object tag) { 224 | View view = getView(viewId); 225 | view.setTag(key, tag); 226 | return this; 227 | } 228 | 229 | public ViewHolder setChecked(int viewId, boolean checked) { 230 | Checkable view = (Checkable) getView(viewId); 231 | view.setChecked(checked); 232 | return this; 233 | } 234 | 235 | /** 236 | * 关于事件 237 | */ 238 | public ViewHolder setOnClickListener(int viewId, 239 | View.OnClickListener listener) { 240 | View view = getView(viewId); 241 | view.setOnClickListener(listener); 242 | return this; 243 | } 244 | 245 | public ViewHolder setOnTouchListener(int viewId, 246 | View.OnTouchListener listener) { 247 | View view = getView(viewId); 248 | view.setOnTouchListener(listener); 249 | return this; 250 | } 251 | 252 | public ViewHolder setOnLongClickListener(int viewId, 253 | View.OnLongClickListener listener) { 254 | View view = getView(viewId); 255 | view.setOnLongClickListener(listener); 256 | return this; 257 | } 258 | 259 | } 260 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/activity/Country6Activity.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.activity; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.view.MenuItemCompat; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.LinearSmoothScroller; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.support.v7.widget.SearchView; 10 | import android.support.v7.widget.Toolbar; 11 | import android.text.TextUtils; 12 | import android.view.Menu; 13 | import android.view.MenuItem; 14 | import android.view.View; 15 | import android.widget.LinearLayout; 16 | import android.widget.TextView; 17 | 18 | import com.lp.sidebar_master.R; 19 | import com.lp.sidebar_master.adapter.CountryRvAdapter; 20 | import com.lp.sidebar_master.base.BaseActivity; 21 | import com.lp.sidebar_master.base.mvp.BaseModel; 22 | import com.lp.sidebar_master.presenter.CountryBean; 23 | import com.lp.sidebar_master.presenter.CountryPresenter; 24 | import com.lp.sidebar_master.presenter.CountryView; 25 | import com.lp.sidebar_master.utils.PinYinKit; 26 | import com.lp.sidebar_master.utils.StatusBarUtil; 27 | import com.lp.sidebar_master.widget.WaveSideBar; 28 | 29 | import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; 30 | 31 | import java.util.ArrayList; 32 | import java.util.Collections; 33 | import java.util.Comparator; 34 | import java.util.List; 35 | 36 | import butterknife.BindView; 37 | import butterknife.ButterKnife; 38 | 39 | 40 | /** 41 | * File descripition: 侧滑栏拼音全部显示,有动态效果,拼音字母顶部停留,顶部拼音搜索 42 | * 43 | * @author lp 44 | * @date 2018/8/4 45 | */ 46 | 47 | public class Country6Activity extends BaseActivity implements CountryView, WaveSideBar.OnSelectIndexItemListener { 48 | @BindView(R.id.sidebar) 49 | WaveSideBar mSidebar; 50 | @BindView(R.id.recyclerView) 51 | RecyclerView mRecyclerView; 52 | @BindView(R.id.tv_index) 53 | TextView mTvIndex; 54 | @BindView(R.id.ll_index) 55 | LinearLayout mLlIndex; 56 | @BindView(R.id.toolbar) 57 | Toolbar mToolbar; 58 | 59 | private CountryRvAdapter mAdapter; 60 | private ArrayList mCountryList; 61 | private ArrayList mCountryShowList; 62 | private PinyinComparatorAdmin comparator; 63 | private LinearLayoutManager layoutManager; 64 | 65 | @Override 66 | protected CountryPresenter createPresenter() { 67 | return new CountryPresenter(this); 68 | } 69 | 70 | @Override 71 | protected int getLayoutId() { 72 | return R.layout.activity_country5; 73 | } 74 | 75 | 76 | @Override 77 | protected void initData() { 78 | StatusBarUtil.setColor(this, getResources().getColor(R.color.colorPrimary), 0); 79 | 80 | setSupportActionBar(mToolbar); 81 | mSidebar.setOnSelectIndexItemListener(this); 82 | comparator = new PinyinComparatorAdmin(); 83 | mCountryList = new ArrayList<>(); 84 | mCountryShowList = new ArrayList<>(); 85 | 86 | mPresenter.internationalCode(); 87 | } 88 | 89 | @Override 90 | public boolean onCreateOptionsMenu(Menu menu) { 91 | getMenuInflater().inflate(R.menu.menu_search_view, menu); 92 | 93 | //找到searchView 94 | MenuItem searchItem = menu.findItem(R.id.action_search); 95 | SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); 96 | 97 | // searchView.setSubmitButtonEnabled(true);//显示提交按钮 98 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 99 | @Override 100 | public boolean onQueryTextSubmit(String query) { 101 | //提交按钮的点击事件 102 | return true; 103 | } 104 | 105 | @Override 106 | public boolean onQueryTextChange(String newText) { 107 | //当输入框内容改变的时候回调 108 | try { 109 | filerData(newText.toString()); 110 | } catch (BadHanyuPinyinOutputFormatCombination e) { 111 | e.printStackTrace(); 112 | } 113 | return true; 114 | } 115 | }); 116 | return super.onCreateOptionsMenu(menu); 117 | } 118 | 119 | 120 | @Override 121 | public void onInternationalCodeSuccess(BaseModel> o) { 122 | mCountryList.clear(); 123 | mCountryList.addAll(o.getData()); 124 | 125 | mCountryShowList = (ArrayList) mCountryList.clone(); 126 | initDatas(mCountryShowList); 127 | } 128 | 129 | private void initDatas(List mList) { 130 | String[] strings = new String[mList.size()]; 131 | for (int i = 0; i < mList.size(); i++) { 132 | strings[i] = new String(mList.get(i).getName()); 133 | } 134 | try { 135 | mCountryShowList = (ArrayList) filledData(strings).clone(); 136 | mCountryList.clear(); 137 | mCountryList.addAll(mCountryShowList); 138 | } catch (BadHanyuPinyinOutputFormatCombination e1) { 139 | e1.printStackTrace(); 140 | } 141 | 142 | //创建布局管理 143 | layoutManager = new LinearLayoutManager(mContext); 144 | layoutManager.setOrientation(LinearLayoutManager.VERTICAL); 145 | mRecyclerView.setLayoutManager(layoutManager); 146 | 147 | mAdapter = new CountryRvAdapter(R.layout.item_country, mCountryShowList); 148 | mRecyclerView.setAdapter(mAdapter); 149 | mRecyclerView.addOnScrollListener(new mScrollListener()); 150 | } 151 | 152 | private class mScrollListener extends RecyclerView.OnScrollListener { 153 | 154 | private int mFlowHeight = 0; 155 | private int mCurrentPosition = -1; 156 | 157 | @Override 158 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 159 | if (mLlIndex != null || mFlowHeight < 1) { 160 | mFlowHeight = mLlIndex.getMeasuredHeight(); 161 | } 162 | } 163 | 164 | @Override 165 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 166 | int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition(); 167 | View view = layoutManager.findViewByPosition(firstVisibleItemPosition + 1); 168 | 169 | if (view != null) { 170 | int section = mCountryShowList.get(firstVisibleItemPosition + 1).getSortLetters().charAt(0); 171 | if (view.getTop() <= mFlowHeight && firstVisibleItemPosition + 1 == getPositionForSection(mCountryShowList,section)) { 172 | mLlIndex.setY(view.getTop() - mFlowHeight); 173 | } else { 174 | mLlIndex.setY(0); 175 | } 176 | } 177 | 178 | if (mCurrentPosition != firstVisibleItemPosition) { 179 | mCurrentPosition = firstVisibleItemPosition; 180 | if (mCountryShowList.size() > 0) { 181 | mTvIndex.setText(mCountryShowList.get(mCurrentPosition).getSortLetters()); 182 | mLlIndex.setVisibility(View.VISIBLE); 183 | } else { 184 | mLlIndex.setVisibility(View.GONE); 185 | } 186 | } 187 | } 188 | } 189 | 190 | /** 191 | * 方法含义:将当前字母传入方法体中, 来获取当前字母在集合中第一次出现的位置position 如果等于当前item的position,UI字母栏 192 | * 显示,如果不是,UI字母栏隐藏 193 | * 194 | * @param section 195 | * @return 对应集合中第一个出现的字母 196 | */ 197 | public static int getPositionForSection(List mList,int section) { 198 | for (int i = 0; i < mList.size(); i++) { 199 | String sortStr = mList.get(i).getSortLetters(); 200 | char firstChar = sortStr.toUpperCase().charAt(0); 201 | if (firstChar == section) { 202 | return i; 203 | } 204 | } 205 | return -1; 206 | } 207 | 208 | //排序 209 | private ArrayList filledData(String[] date) throws BadHanyuPinyinOutputFormatCombination { 210 | for (int i = 0; i < date.length; i++) { 211 | mCountryList.get(i).setName(date[i]); 212 | String pinyin = PinYinKit.getPingYin(date[i]); 213 | String sortString = ""; 214 | if (!TextUtils.isEmpty(pinyin)) { 215 | sortString = pinyin.substring(0, 1).toUpperCase(); 216 | } 217 | if (sortString.matches("[A-Z]")) { 218 | mCountryList.get(i).setSortLetters(sortString.toUpperCase()); 219 | } else { 220 | mCountryList.get(i).setSortLetters("#"); 221 | } 222 | } 223 | //排序 224 | Collections.sort(mCountryList, new PinyinComparatorAdmin()); 225 | 226 | for (int i = 0; i < mCountryList.size(); i++) { 227 | if (i == getPositionForSection(mCountryList,mCountryList.get(i).getSortLetters().charAt(0))) { 228 | mCountryList.get(i).setLetter(true); 229 | } else { 230 | mCountryList.get(i).setLetter(false); 231 | } 232 | } 233 | return mCountryList; 234 | } 235 | 236 | @Override 237 | protected void onCreate(Bundle savedInstanceState) { 238 | super.onCreate(savedInstanceState); 239 | // TODO: add setContentView(...) invocation 240 | ButterKnife.bind(this); 241 | } 242 | 243 | 244 | @Override 245 | public void onSelectIndexItem(String str) { 246 | try { 247 | int position = getPositionForSection(mCountryShowList,str.charAt(0)); 248 | if (position != -1) { 249 | /** 250 | * 直接到指定位置 251 | */ 252 | // layoutManager.scrollToPositionWithOffset(position, 0); 253 | ((LinearLayoutManager)mRecyclerView.getLayoutManager()).scrollToPositionWithOffset(position,0); 254 | /** 255 | * 滚动到指定位置(有滚动效果) 256 | */ 257 | // LinearSmoothScroller s1 = new TopSmoothScroller(this); 258 | // s1.setTargetPosition(position); 259 | // layoutManager.startSmoothScroll(s1); 260 | } 261 | } catch (Exception e) { 262 | e.printStackTrace(); 263 | } 264 | } 265 | 266 | 267 | public class PinyinComparatorAdmin implements Comparator { 268 | @Override 269 | public int compare(CountryBean o1, CountryBean o2) { 270 | if (o1.getSortLetters().equals("@") || o2.getSortLetters().equals("#")) { 271 | return -1; 272 | } else if (o1.getSortLetters().equals("#") || o2.getSortLetters().equals("@")) { 273 | return 1; 274 | } else { 275 | return o1.getSortLetters().compareTo(o2.getSortLetters()); 276 | } 277 | } 278 | } 279 | 280 | public class TopSmoothScroller extends LinearSmoothScroller { 281 | TopSmoothScroller(Context context) { 282 | super(context); 283 | } 284 | 285 | @Override 286 | protected int getHorizontalSnapPreference() { 287 | return SNAP_TO_START; 288 | } 289 | 290 | @Override 291 | protected int getVerticalSnapPreference() { 292 | return SNAP_TO_START; 293 | } 294 | } 295 | 296 | private void filerData(String str) throws BadHanyuPinyinOutputFormatCombination { 297 | if (TextUtils.isEmpty(str)) { 298 | mCountryShowList.clear(); 299 | mCountryShowList.addAll(mCountryList); 300 | } else { 301 | mCountryShowList.clear(); 302 | for (CountryBean ms : mCountryList) { 303 | String name = ms.getName(); 304 | String code = ms.getCode(); 305 | if (name.indexOf(str.toString()) != -1 306 | || PinYinKit.getPingYin(name).startsWith(str.toString()) 307 | || PinYinKit.getPingYin(name).startsWith(str.toUpperCase().toString()) 308 | || name.contains(str) 309 | 310 | || PinYinKit.getPingYin(code).startsWith(str.toString()) 311 | || PinYinKit.getPingYin(code).startsWith(str.toUpperCase().toString()) 312 | || code.contains(str) 313 | ) { 314 | mCountryShowList.add(ms); 315 | } 316 | } 317 | } 318 | PinYinKit.initLetter(mCountryShowList); 319 | mAdapter.notifyDataSetChanged(); 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/widget/WaveSideBar.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.RectF; 9 | import android.util.AttributeSet; 10 | import android.util.DisplayMetrics; 11 | import android.util.TypedValue; 12 | import android.view.MotionEvent; 13 | import android.view.View; 14 | 15 | 16 | import com.lp.sidebar_master.R; 17 | 18 | import java.util.Arrays; 19 | 20 | 21 | public class WaveSideBar extends View { 22 | private final static int DEFAULT_TEXT_SIZE = 14; // sp 23 | private final static int DEFAULT_MAX_OFFSET = 80; //dp 24 | 25 | private final static String[] DEFAULT_INDEX_ITEMS = {"A", "B", "C", "D", "E", "F", "G", "H", "I", 26 | "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}; 27 | 28 | private String[] mIndexItems; 29 | 30 | /** 31 | * the index in {@link #mIndexItems} of the current selected index item, 32 | * it's reset to -1 when the finger up 33 | */ 34 | private int mCurrentIndex = -1; 35 | 36 | /** 37 | * Y coordinate of the point where finger is touching, 38 | * the baseline is top of {@link #mStartTouchingArea} 39 | * it's reset to -1 when the finger up 40 | */ 41 | private float mCurrentY = -1; 42 | 43 | private Paint mPaint; 44 | private int mTextColor; 45 | private float mTextSize; 46 | 47 | /** 48 | * the height of each index item 49 | */ 50 | private float mIndexItemHeight; 51 | 52 | /** 53 | * offset of the current selected index item 54 | */ 55 | private float mMaxOffset; 56 | 57 | /** 58 | * {@link #mStartTouching} will be set to true when {@link MotionEvent#ACTION_DOWN} 59 | * happens in this area, and the side bar should start working. 60 | */ 61 | private RectF mStartTouchingArea = new RectF(); 62 | 63 | /** 64 | * height and width of {@link #mStartTouchingArea} 65 | */ 66 | private float mBarHeight; 67 | private float mBarWidth; 68 | 69 | /** 70 | * Flag that the finger is starting touching. 71 | * If true, it means the {@link MotionEvent#ACTION_DOWN} happened but 72 | * {@link MotionEvent#ACTION_UP} not yet. 73 | */ 74 | private boolean mStartTouching = false; 75 | 76 | /** 77 | * if true, the {@link OnSelectIndexItemListener#onSelectIndexItem(String)} 78 | * will not be called until the finger up. 79 | * if false, it will be called when the finger down, up and move. 80 | */ 81 | private boolean mLazyRespond = false; 82 | 83 | /** 84 | * the position of the side bar, default is {@link #POSITION_RIGHT}. 85 | * You can set it to {@link #POSITION_LEFT} for people who use phone with left hand. 86 | */ 87 | private int mSideBarPosition; 88 | public static final int POSITION_RIGHT = 0; 89 | public static final int POSITION_LEFT = 1; 90 | 91 | /** 92 | * the alignment of items, default is {@link #TEXT_ALIGN_CENTER}. 93 | */ 94 | private int mTextAlignment; 95 | public static final int TEXT_ALIGN_CENTER = 0; 96 | public static final int TEXT_ALIGN_LEFT = 1; 97 | public static final int TEXT_ALIGN_RIGHT = 2; 98 | 99 | 100 | /** 101 | * observe the current selected index item 102 | */ 103 | private OnSelectIndexItemListener onSelectIndexItemListener; 104 | 105 | /** 106 | * the baseline of the first index item text to draw 107 | */ 108 | private float mFirstItemBaseLineY; 109 | 110 | /** 111 | * for {@link #dp2px(int)} and {@link #sp2px(int)} 112 | */ 113 | private DisplayMetrics mDisplayMetrics; 114 | 115 | 116 | public WaveSideBar(Context context) { 117 | this(context, null); 118 | } 119 | 120 | public WaveSideBar(Context context, AttributeSet attrs) { 121 | this(context, attrs, 0); 122 | } 123 | 124 | public WaveSideBar(Context context, AttributeSet attrs, int defStyleAttr) { 125 | super(context, attrs, defStyleAttr); 126 | mDisplayMetrics = context.getResources().getDisplayMetrics(); 127 | 128 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WaveSideBar); 129 | mLazyRespond = typedArray.getBoolean(R.styleable.WaveSideBar_sidebar_lazy_respond, false); 130 | mTextColor = typedArray.getColor(R.styleable.WaveSideBar_sidebar_text_color, Color.GRAY); 131 | mTextSize = typedArray.getDimension(R.styleable.WaveSideBar_sidebar_text_size, sp2px(DEFAULT_TEXT_SIZE)); 132 | mMaxOffset = typedArray.getDimension(R.styleable.WaveSideBar_sidebar_max_offset, dp2px(DEFAULT_MAX_OFFSET)); 133 | mSideBarPosition = typedArray.getInt(R.styleable.WaveSideBar_sidebar_position, POSITION_RIGHT); 134 | mTextAlignment = typedArray.getInt(R.styleable.WaveSideBar_sidebar_text_alignment, TEXT_ALIGN_CENTER); 135 | typedArray.recycle(); 136 | 137 | mIndexItems = DEFAULT_INDEX_ITEMS; 138 | 139 | initPaint(); 140 | } 141 | 142 | private void initPaint() { 143 | mPaint = new Paint(); 144 | mPaint.setAntiAlias(true); 145 | mPaint.setColor(mTextColor); 146 | mPaint.setTextSize(mTextSize); 147 | switch (mTextAlignment) { 148 | case TEXT_ALIGN_CENTER: mPaint.setTextAlign(Paint.Align.CENTER); break; 149 | case TEXT_ALIGN_LEFT: mPaint.setTextAlign(Paint.Align.LEFT); break; 150 | case TEXT_ALIGN_RIGHT: mPaint.setTextAlign(Paint.Align.RIGHT); break; 151 | } 152 | } 153 | 154 | @Override 155 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 156 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 157 | 158 | int height = MeasureSpec.getSize(heightMeasureSpec); 159 | int width = MeasureSpec.getSize(widthMeasureSpec); 160 | 161 | Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); 162 | mIndexItemHeight = fontMetrics.bottom - fontMetrics.top; 163 | mBarHeight = mIndexItems.length * mIndexItemHeight; 164 | 165 | // calculate the width of the longest text as the width of side bar 166 | for (String indexItem : mIndexItems) { 167 | mBarWidth = Math.max(mBarWidth, mPaint.measureText(indexItem)); 168 | } 169 | 170 | float areaLeft = (mSideBarPosition == POSITION_LEFT) ? 0 : (width - mBarWidth - getPaddingRight()); 171 | float areaRight = (mSideBarPosition == POSITION_LEFT) ? (getPaddingLeft() + areaLeft + mBarWidth) : width; 172 | float areaTop = height/2 - mBarHeight/2; 173 | float areaBottom = areaTop + mBarHeight; 174 | mStartTouchingArea.set( 175 | areaLeft, 176 | areaTop, 177 | areaRight, 178 | areaBottom); 179 | 180 | // the baseline Y of the first item' text to draw 181 | mFirstItemBaseLineY = (height/2 - mIndexItems.length*mIndexItemHeight/2) 182 | + (mIndexItemHeight/2 - (fontMetrics.descent-fontMetrics.ascent)/2) 183 | - fontMetrics.ascent; 184 | } 185 | 186 | @Override 187 | protected void onDraw(Canvas canvas) { 188 | super.onDraw(canvas); 189 | 190 | // draw each item 191 | for (int i = 0, mIndexItemsLength = mIndexItems.length; i < mIndexItemsLength; i++) { 192 | float baseLineY = mFirstItemBaseLineY + mIndexItemHeight*i; 193 | 194 | // calculate the scale factor of the item to draw 195 | float scale = getItemScale(i); 196 | 197 | int alphaScale = (i == mCurrentIndex) ? (255) : (int) (255 * (1-scale)); 198 | mPaint.setAlpha(alphaScale); 199 | 200 | mPaint.setTextSize(mTextSize + mTextSize*scale); 201 | 202 | float baseLineX = 0f; 203 | if (mSideBarPosition == POSITION_LEFT) { 204 | switch (mTextAlignment) { 205 | case TEXT_ALIGN_CENTER: 206 | baseLineX = getPaddingLeft() + mBarWidth/2 + mMaxOffset*scale; 207 | break; 208 | case TEXT_ALIGN_LEFT: 209 | baseLineX = getPaddingLeft() + mMaxOffset*scale; 210 | break; 211 | case TEXT_ALIGN_RIGHT: 212 | baseLineX = getPaddingLeft() + mBarWidth + mMaxOffset*scale; 213 | break; 214 | } 215 | } else { 216 | switch (mTextAlignment) { 217 | case TEXT_ALIGN_CENTER: 218 | baseLineX = getWidth() - getPaddingRight() - mBarWidth/2 - mMaxOffset*scale; 219 | break; 220 | case TEXT_ALIGN_RIGHT: 221 | baseLineX = getWidth() - getPaddingRight() - mMaxOffset*scale; 222 | break; 223 | case TEXT_ALIGN_LEFT: 224 | baseLineX = getWidth() - getPaddingRight() - mBarWidth - mMaxOffset*scale; 225 | break; 226 | } 227 | } 228 | 229 | // draw 230 | canvas.drawText( 231 | mIndexItems[i], //item text to draw 232 | baseLineX, //baseLine X 233 | baseLineY, // baseLine Y 234 | mPaint); 235 | } 236 | 237 | // reset paint 238 | mPaint.setAlpha(255); 239 | mPaint.setTextSize(mTextSize); 240 | } 241 | 242 | /** 243 | * calculate the scale factor of the item to draw 244 | * 245 | * @param index the index of the item in array {@link #mIndexItems} 246 | * @return the scale factor of the item to draw 247 | */ 248 | private float getItemScale(int index) { 249 | float scale = 0; 250 | if (mCurrentIndex != -1) { 251 | float distance = Math.abs(mCurrentY - (mIndexItemHeight*index+mIndexItemHeight/2)) / mIndexItemHeight; 252 | scale = 1 - distance*distance/16; 253 | scale = Math.max(scale, 0); 254 | } 255 | return scale; 256 | } 257 | 258 | @Override 259 | public boolean onTouchEvent(MotionEvent event) { 260 | if (mIndexItems.length == 0) { 261 | return super.onTouchEvent(event); 262 | } 263 | 264 | float eventY = event.getY(); 265 | float eventX = event.getX(); 266 | mCurrentIndex = getSelectedIndex(eventY); 267 | 268 | switch (event.getAction()) { 269 | case MotionEvent.ACTION_DOWN: 270 | if (mStartTouchingArea.contains(eventX, eventY)) { 271 | mStartTouching = true; 272 | if (!mLazyRespond && onSelectIndexItemListener != null) { 273 | onSelectIndexItemListener.onSelectIndexItem(mIndexItems[mCurrentIndex]); 274 | } 275 | invalidate(); 276 | return true; 277 | } else { 278 | mCurrentIndex = -1; 279 | return false; 280 | } 281 | 282 | case MotionEvent.ACTION_MOVE: 283 | if (mStartTouching && !mLazyRespond && onSelectIndexItemListener != null) { 284 | onSelectIndexItemListener.onSelectIndexItem(mIndexItems[mCurrentIndex]); 285 | } 286 | invalidate(); 287 | return true; 288 | 289 | case MotionEvent.ACTION_UP: 290 | case MotionEvent.ACTION_CANCEL: 291 | if (mLazyRespond && onSelectIndexItemListener != null) { 292 | onSelectIndexItemListener.onSelectIndexItem(mIndexItems[mCurrentIndex]); 293 | } 294 | mCurrentIndex = -1; 295 | mStartTouching = false; 296 | invalidate(); 297 | return true; 298 | } 299 | 300 | return super.onTouchEvent(event); 301 | } 302 | 303 | private int getSelectedIndex(float eventY) { 304 | mCurrentY = eventY - (getHeight()/2 - mBarHeight /2); 305 | if (mCurrentY <= 0) { 306 | return 0; 307 | } 308 | 309 | int index = (int) (mCurrentY / this.mIndexItemHeight); 310 | if (index >= this.mIndexItems.length) { 311 | index = this.mIndexItems.length - 1; 312 | } 313 | return index; 314 | } 315 | 316 | private float dp2px(int dp) { 317 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, this.mDisplayMetrics); 318 | } 319 | 320 | private float sp2px(int sp) { 321 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, this.mDisplayMetrics); 322 | } 323 | 324 | public void setIndexItems(String... indexItems) { 325 | mIndexItems = Arrays.copyOf(indexItems, indexItems.length); 326 | requestLayout(); 327 | } 328 | 329 | public void setTextColor(int color) { 330 | mTextColor = color; 331 | mPaint.setColor(color); 332 | invalidate(); 333 | } 334 | 335 | public void setPosition(int position) { 336 | if (position != POSITION_RIGHT && position != POSITION_LEFT) { 337 | throw new IllegalArgumentException("the position must be POSITION_RIGHT or POSITION_LEFT"); 338 | } 339 | 340 | mSideBarPosition = position; 341 | requestLayout(); 342 | } 343 | 344 | public void setMaxOffset(int offset) { 345 | mMaxOffset = offset; 346 | invalidate(); 347 | } 348 | 349 | public void setLazyRespond(boolean lazyRespond) { 350 | mLazyRespond = lazyRespond; 351 | } 352 | 353 | public void setTextAlign(int align) { 354 | if (mTextAlignment == align) { 355 | return; 356 | } 357 | switch (align) { 358 | case TEXT_ALIGN_CENTER: mPaint.setTextAlign(Paint.Align.CENTER); break; 359 | case TEXT_ALIGN_LEFT: mPaint.setTextAlign(Paint.Align.LEFT); break; 360 | case TEXT_ALIGN_RIGHT: mPaint.setTextAlign(Paint.Align.RIGHT); break; 361 | default: 362 | throw new IllegalArgumentException( 363 | "the alignment must be TEXT_ALIGN_CENTER, TEXT_ALIGN_LEFT or TEXT_ALIGN_RIGHT"); 364 | } 365 | mTextAlignment = align; 366 | invalidate(); 367 | } 368 | 369 | public void setTextSize(float size) { 370 | if (mTextSize == size) { 371 | return; 372 | } 373 | mTextSize = size; 374 | mPaint.setTextSize(size); 375 | invalidate(); 376 | } 377 | 378 | public void setOnSelectIndexItemListener(OnSelectIndexItemListener onSelectIndexItemListener) { 379 | this.onSelectIndexItemListener = onSelectIndexItemListener; 380 | } 381 | 382 | public interface OnSelectIndexItemListener { 383 | void onSelectIndexItem(String index); 384 | } 385 | } -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/base/api/ApiRetrofit.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.base.api; 2 | 3 | 4 | import com.google.gson.Gson; 5 | import com.lp.sidebar_master.base.BaseContent; 6 | import com.lp.sidebar_master.utils.L; 7 | 8 | import java.io.IOException; 9 | import java.nio.charset.Charset; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | import okhttp3.Interceptor; 13 | import okhttp3.MediaType; 14 | import okhttp3.OkHttpClient; 15 | import okhttp3.Protocol; 16 | import okhttp3.Request; 17 | import okhttp3.RequestBody; 18 | import okhttp3.Response; 19 | import okhttp3.ResponseBody; 20 | import okio.Buffer; 21 | import retrofit2.Retrofit; 22 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; 23 | import retrofit2.converter.gson.GsonConverterFactory; 24 | 25 | import static okhttp3.internal.Util.UTF_8; 26 | 27 | 28 | /** 29 | * File descripition: 30 | * 31 | * @author lp 32 | * @date 2018/6/19 33 | */ 34 | 35 | public class ApiRetrofit { 36 | public final String BASE_SERVER_URL = BaseContent.baseUrl; 37 | 38 | private static ApiRetrofit apiRetrofit; 39 | private Retrofit retrofit; 40 | private ApiServer apiServer; 41 | private static final int DEFAULT_TIMEOUT = 15; 42 | 43 | public ApiRetrofit() { 44 | OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); 45 | 46 | httpClientBuilder 47 | .addInterceptor(interceptor) 48 | .addInterceptor(new MockInterceptor()) 49 | //设置请求超时时长 50 | .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) 51 | .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) 52 | .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) 53 | .retryOnConnectionFailure(true)//错误重联 54 | ; 55 | 56 | retrofit = new Retrofit.Builder() 57 | .baseUrl(BASE_SERVER_URL) 58 | .addConverterFactory(GsonConverterFactory.create()) 59 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 60 | .client(httpClientBuilder.build()) 61 | .build(); 62 | 63 | apiServer = retrofit.create(ApiServer.class); 64 | } 65 | 66 | public static ApiRetrofit getInstance() { 67 | if (apiRetrofit == null) { 68 | synchronized (Object.class) { 69 | if (apiRetrofit == null) { 70 | apiRetrofit = new ApiRetrofit(); 71 | } 72 | } 73 | } 74 | return apiRetrofit; 75 | } 76 | 77 | public ApiServer getApiService() { 78 | return apiServer; 79 | } 80 | 81 | /** 82 | * 请求访问quest 83 | * response拦截器 84 | */ 85 | private Interceptor interceptor = new Interceptor() { 86 | @Override 87 | public Response intercept(Chain chain) throws IOException { 88 | Request request = chain.request(); 89 | long startTime = System.currentTimeMillis(); 90 | Response response = chain.proceed(chain.request()); 91 | long endTime = System.currentTimeMillis(); 92 | long duration = endTime - startTime; 93 | MediaType mediaType = response.body().contentType(); 94 | String content = response.body().string(); 95 | // analyzeJson("data", "", content); 96 | L.e("----------Request Start----------------"); 97 | printParams(request.body()); 98 | L.e("| " + request.toString() + "===========" + request.headers().toString()); 99 | L.e(content); 100 | L.e("----------Request End:" + duration + "毫秒----------"); 101 | 102 | return response.newBuilder() 103 | .body(ResponseBody.create(mediaType, content)) 104 | .build(); 105 | } 106 | }; 107 | 108 | /** 109 | * 请求参数日志打印 110 | * 111 | * @param body 112 | */ 113 | private void printParams(RequestBody body) { 114 | if (body != null) { 115 | Buffer buffer = new Buffer(); 116 | try { 117 | body.writeTo(buffer); 118 | Charset charset = Charset.forName("UTF-8"); 119 | MediaType contentType = body.contentType(); 120 | if (contentType != null) { 121 | charset = contentType.charset(UTF_8); 122 | } 123 | String params = buffer.readString(charset); 124 | L.e("请求参数: | " + params); 125 | } catch (IOException e) { 126 | e.printStackTrace(); 127 | } 128 | } 129 | } 130 | 131 | 132 | public class MockInterceptor implements Interceptor{ 133 | @Override 134 | public Response intercept(Chain chain) throws IOException { 135 | Gson gson = new Gson(); 136 | Response response = null; 137 | Response.Builder responseBuilder = new Response.Builder() 138 | .code(200) 139 | .message("") 140 | .request(chain.request()) 141 | .protocol(Protocol.HTTP_1_0) 142 | .addHeader("content-type", "application/json"); 143 | Request request = chain.request(); 144 | if(request.url().toString().contains(BASE_SERVER_URL)) { //拦截指定地址 145 | String responseString = "{\n" + 146 | "\t\"code\": 0,\n" + 147 | "\t\"result\": [{\n" + 148 | "\t\t\"code\": 86,\n" + 149 | "\t\t\"name\": \"\\u4e2d\\u56fd\\u5927\\u9646\"\n" + 150 | "\t}, {\n" + 151 | "\t\t\"code\": 1,\n" + 152 | "\t\t\"name\": \"\\u7f8e\\u56fd\"\n" + 153 | "\t}, {\n" + 154 | "\t\t\"code\": 81,\n" + 155 | "\t\t\"name\": \"\\u65e5\\u672c\"\n" + 156 | "\t}, {\n" + 157 | "\t\t\"code\": 49,\n" + 158 | "\t\t\"name\": \"\\u5fb7\\u56fd\"\n" + 159 | "\t}, {\n" + 160 | "\t\t\"code\": 44,\n" + 161 | "\t\t\"name\": \"\\u82f1\\u56fd\"\n" + 162 | "\t}, {\n" + 163 | "\t\t\"code\": 33,\n" + 164 | "\t\t\"name\": \"\\u6cd5\\u56fd\"\n" + 165 | "\t}, {\n" + 166 | "\t\t\"code\": 91,\n" + 167 | "\t\t\"name\": \"\\u5370\\u5ea6\"\n" + 168 | "\t}, {\n" + 169 | "\t\t\"code\": 39,\n" + 170 | "\t\t\"name\": \"\\u610f\\u5927\\u5229\"\n" + 171 | "\t}, {\n" + 172 | "\t\t\"code\": 55,\n" + 173 | "\t\t\"name\": \"\\u5df4\\u897f\"\n" + 174 | "\t}, {\n" + 175 | "\t\t\"code\": 1,\n" + 176 | "\t\t\"name\": \"\\u52a0\\u62ff\\u5927\"\n" + 177 | "\t}, {\n" + 178 | "\t\t\"code\": 82,\n" + 179 | "\t\t\"name\": \"\\u97e9\\u56fd\"\n" + 180 | "\t}, {\n" + 181 | "\t\t\"code\": 34,\n" + 182 | "\t\t\"name\": \"\\u897f\\u73ed\\u7259\"\n" + 183 | "\t}, {\n" + 184 | "\t\t\"code\": 61,\n" + 185 | "\t\t\"name\": \"\\u6fb3\\u5927\\u5229\\u4e9a\"\n" + 186 | "\t}, {\n" + 187 | "\t\t\"code\": 52,\n" + 188 | "\t\t\"name\": \"\\u58a8\\u897f\\u54e5\"\n" + 189 | "\t}, {\n" + 190 | "\t\t\"code\": 73,\n" + 191 | "\t\t\"name\": \"\\u4fc4\\u7f57\\u65af\"\n" + 192 | "\t}, {\n" + 193 | "\t\t\"code\": 62,\n" + 194 | "\t\t\"name\": \"\\u5370\\u5ea6\\u5c3c\\u897f\\u4e9a\"\n" + 195 | "\t}, {\n" + 196 | "\t\t\"code\": 31,\n" + 197 | "\t\t\"name\": \"\\u8377\\u5170\"\n" + 198 | "\t}, {\n" + 199 | "\t\t\"code\": 90,\n" + 200 | "\t\t\"name\": \"\\u571f\\u8033\\u5176\"\n" + 201 | "\t}, {\n" + 202 | "\t\t\"code\": 41,\n" + 203 | "\t\t\"name\": \"\\u745e\\u58eb\"\n" + 204 | "\t}, {\n" + 205 | "\t\t\"code\": 966,\n" + 206 | "\t\t\"name\": \"\\u6c99\\u7279\\u963f\\u62c9\\u4f2f\"\n" + 207 | "\t}, {\n" + 208 | "\t\t\"code\": 54,\n" + 209 | "\t\t\"name\": \"\\u963f\\u6839\\u5ef7\"\n" + 210 | "\t}, {\n" + 211 | "\t\t\"code\": 886,\n" + 212 | "\t\t\"name\": \"\\u4e2d\\u56fd\\u53f0\\u6e7e\"\n" + 213 | "\t}, {\n" + 214 | "\t\t\"code\": 48,\n" + 215 | "\t\t\"name\": \"\\u6ce2\\u5170\"\n" + 216 | "\t}, {\n" + 217 | "\t\t\"code\": 46,\n" + 218 | "\t\t\"name\": \"\\u745e\\u5178\"\n" + 219 | "\t}, {\n" + 220 | "\t\t\"code\": 234,\n" + 221 | "\t\t\"name\": \"\\u5c3c\\u65e5\\u5229\\u4e9a\"\n" + 222 | "\t}, {\n" + 223 | "\t\t\"code\": 32,\n" + 224 | "\t\t\"name\": \"\\u6bd4\\u5229\\u65f6\"\n" + 225 | "\t}, {\n" + 226 | "\t\t\"code\": 98,\n" + 227 | "\t\t\"name\": \"\\u4f0a\\u6717\"\n" + 228 | "\t}, {\n" + 229 | "\t\t\"code\": 47,\n" + 230 | "\t\t\"name\": \"\\u632a\\u5a01\"\n" + 231 | "\t}, {\n" + 232 | "\t\t\"code\": 66,\n" + 233 | "\t\t\"name\": \"\\u6cf0\\u56fd\"\n" + 234 | "\t}, {\n" + 235 | "\t\t\"code\": 43,\n" + 236 | "\t\t\"name\": \"\\u5965\\u5730\\u5229\"\n" + 237 | "\t}, {\n" + 238 | "\t\t\"code\": 60,\n" + 239 | "\t\t\"name\": \"\\u9a6c\\u6765\\u897f\\u4e9a\"\n" + 240 | "\t}, {\n" + 241 | "\t\t\"code\": 63,\n" + 242 | "\t\t\"name\": \"\\u83f2\\u5f8b\\u5bbe\"\n" + 243 | "\t}, {\n" + 244 | "\t\t\"code\": 27,\n" + 245 | "\t\t\"name\": \"\\u5357\\u975e\"\n" + 246 | "\t}, {\n" + 247 | "\t\t\"code\": 852,\n" + 248 | "\t\t\"name\": \"\\u4e2d\\u56fd\\u9999\\u6e2f\"\n" + 249 | "\t}, {\n" + 250 | "\t\t\"code\": 972,\n" + 251 | "\t\t\"name\": \"\\u4ee5\\u8272\\u5217\"\n" + 252 | "\t}, {\n" + 253 | "\t\t\"code\": 65,\n" + 254 | "\t\t\"name\": \"\\u65b0\\u52a0\\u5761\"\n" + 255 | "\t}, {\n" + 256 | "\t\t\"code\": 45,\n" + 257 | "\t\t\"name\": \"\\u4e39\\u9ea6\"\n" + 258 | "\t}, {\n" + 259 | "\t\t\"code\": 57,\n" + 260 | "\t\t\"name\": \"\\u54e5\\u4f26\\u6bd4\\u4e9a\"\n" + 261 | "\t}, {\n" + 262 | "\t\t\"code\": 353,\n" + 263 | "\t\t\"name\": \"\\u7231\\u5c14\\u5170\\u5171\\u548c\\u56fd\"\n" + 264 | "\t}, {\n" + 265 | "\t\t\"code\": 56,\n" + 266 | "\t\t\"name\": \"\\u667a\\u5229\"\n" + 267 | "\t}, {\n" + 268 | "\t\t\"code\": 358,\n" + 269 | "\t\t\"name\": \"\\u82ac\\u5170\"\n" + 270 | "\t}, {\n" + 271 | "\t\t\"code\": 880,\n" + 272 | "\t\t\"name\": \"\\u5b5f\\u52a0\\u62c9\\u56fd\"\n" + 273 | "\t}, {\n" + 274 | "\t\t\"code\": 84,\n" + 275 | "\t\t\"name\": \"\\u8d8a\\u5357\"\n" + 276 | "\t}, {\n" + 277 | "\t\t\"code\": 351,\n" + 278 | "\t\t\"name\": \"\\u8461\\u8404\\u7259\"\n" + 279 | "\t}, {\n" + 280 | "\t\t\"code\": 30,\n" + 281 | "\t\t\"name\": \"\\u5e0c\\u814a\"\n" + 282 | "\t}, {\n" + 283 | "\t\t\"code\": 420,\n" + 284 | "\t\t\"name\": \"\\u6377\\u514b\"\n" + 285 | "\t}, {\n" + 286 | "\t\t\"code\": 213,\n" + 287 | "\t\t\"name\": \"\\u963f\\u5c14\\u53ca\\u5229\\u4e9a\"\n" + 288 | "\t}, {\n" + 289 | "\t\t\"code\": 51,\n" + 290 | "\t\t\"name\": \"\\u79d8\\u9c81\"\n" + 291 | "\t}, {\n" + 292 | "\t\t\"code\": 964,\n" + 293 | "\t\t\"name\": \"\\u4f0a\\u62c9\\u514b\"\n" + 294 | "\t}, {\n" + 295 | "\t\t\"code\": 853,\n" + 296 | "\t\t\"name\": \"\\u4e2d\\u56fd\\u6fb3\\u95e8\"\n" + 297 | "\t}, {\n" + 298 | "\t\t\"code\": \"1-649\",\n" + 299 | "\t\t\"name\": \"\\u571f\\u514b\\u51ef\\u53ef\\u7fa4\\u5c9b\"\n" + 300 | "\t}, {\n" + 301 | "\t\t\"code\": \"1-787\",\n" + 302 | "\t\t\"name\": \"\\u6ce2\\u591a\\u9ece\\u5404\"\n" + 303 | "\t}, {\n" + 304 | "\t\t\"code\": \"1-684\",\n" + 305 | "\t\t\"name\": \"\\u7f8e\\u5c5e\\u8428\\u6469\\u4e9a\"\n" + 306 | "\t}, {\n" + 307 | "\t\t\"code\": \"1-664\",\n" + 308 | "\t\t\"name\": \"\\u8499\\u585e\\u62c9\\u7279\\u5c9b\"\n" + 309 | "\t}, {\n" + 310 | "\t\t\"code\": \"1-441\",\n" + 311 | "\t\t\"name\": \"\\u767e\\u6155\\u5927\"\n" + 312 | "\t}, {\n" + 313 | "\t\t\"code\": \"1-345\",\n" + 314 | "\t\t\"name\": \"\\u5f00\\u66fc\\u7fa4\\u5c9b\"\n" + 315 | "\t}, {\n" + 316 | "\t\t\"code\": 350,\n" + 317 | "\t\t\"name\": \"\\u76f4\\u5e03\\u7f57\\u9640\"\n" + 318 | "\t}, {\n" + 319 | "\t\t\"code\": 687,\n" + 320 | "\t\t\"name\": \"\\u65b0\\u5580\\u91cc\\u591a\\u5c3c\\u4e9a\"\n" + 321 | "\t}, {\n" + 322 | "\t\t\"code\": 594,\n" + 323 | "\t\t\"name\": \"\\u6cd5\\u5c5e\\u572d\\u4e9a\\u90a3\"\n" + 324 | "\t}, {\n" + 325 | "\t\t\"code\": 689,\n" + 326 | "\t\t\"name\": \"\\u6cd5\\u5c5e\\u6ce2\\u5229\\u5c3c\\u897f\\u4e9a\"\n" + 327 | "\t}, {\n" + 328 | "\t\t\"code\": 596,\n" + 329 | "\t\t\"name\": \"\\u9a6c\\u63d0\\u5c3c\\u514b\"\n" + 330 | "\t}, {\n" + 331 | "\t\t\"code\": 262,\n" + 332 | "\t\t\"name\": \"\\u7559\\u5c3c\\u6c6a\"\n" + 333 | "\t}, {\n" + 334 | "\t\t\"code\": 508,\n" + 335 | "\t\t\"name\": \"\\u5723\\u76ae\\u8036\\u4e0e\\u871c\\u514b\\u9686\\u7fa4\\u5c9b\"\n" + 336 | "\t}],\n" + 337 | "\t\"message\": \"\\u8bf7\\u6c42\\u6210\\u529f\"\n" + 338 | "}"; 339 | responseBuilder.body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()));//将数据设置到body中 340 | response = responseBuilder.build(); //builder模式构建response 341 | }else{ 342 | response = chain.proceed(request); 343 | } 344 | return response; 345 | } 346 | } 347 | 348 | } 349 | -------------------------------------------------------------------------------- /app/src/main/java/com/lp/sidebar_master/utils/StatusBarUtil.java: -------------------------------------------------------------------------------- 1 | package com.lp.sidebar_master.utils; 2 | 3 | /** 4 | * File descripition: 5 | * 6 | * @author lp 7 | * @date 2019/3/8 8 | */ 9 | 10 | import android.annotation.TargetApi; 11 | import android.app.Activity; 12 | import android.content.Context; 13 | import android.graphics.Color; 14 | import android.os.Build; 15 | import android.support.annotation.ColorInt; 16 | import android.support.annotation.IntRange; 17 | import android.support.annotation.NonNull; 18 | import android.support.design.widget.CoordinatorLayout; 19 | import android.support.v4.widget.DrawerLayout; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | import android.view.Window; 23 | import android.view.WindowManager; 24 | import android.widget.LinearLayout; 25 | 26 | 27 | import com.lp.sidebar_master.R; 28 | 29 | import java.lang.reflect.Field; 30 | import java.lang.reflect.Method; 31 | 32 | 33 | /** 34 | * Created by Jaeger on 16/2/14. 35 | *

36 | * Email: chjie.jaeger@gmail.com 37 | * GitHub: https://github.com/laobie 38 | */ 39 | public class StatusBarUtil { 40 | public static final int DEFAULT_STATUS_BAR_ALPHA = 112; 41 | private static final int FAKE_STATUS_BAR_VIEW_ID = R.id.statusbarutil_fake_status_bar_view; 42 | private static final int FAKE_TRANSLUCENT_VIEW_ID = R.id.statusbarutil_translucent_view; 43 | private static final int TAG_KEY_HAVE_SET_OFFSET = -123; 44 | 45 | /** 46 | * 设置状态栏颜色 47 | * 48 | * @param activity 需要设置的 activity 49 | * @param color 状态栏颜色值 50 | */ 51 | public static void setColor(Activity activity, @ColorInt int color) { 52 | setColor(activity, color, DEFAULT_STATUS_BAR_ALPHA); 53 | } 54 | 55 | /** 56 | * 设置状态栏颜色 57 | * 58 | * @param activity 需要设置的activity 59 | * @param color 状态栏颜色值 60 | * @param statusBarAlpha 状态栏透明度 61 | */ 62 | 63 | public static void setColor(Activity activity, @ColorInt int color, @IntRange(from = 0, to = 255) int statusBarAlpha) { 64 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 65 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 66 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 67 | activity.getWindow().setStatusBarColor(calculateStatusColor(color, statusBarAlpha)); 68 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 69 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 70 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); 71 | View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID); 72 | if (fakeStatusBarView != null) { 73 | if (fakeStatusBarView.getVisibility() == View.GONE) { 74 | fakeStatusBarView.setVisibility(View.VISIBLE); 75 | } 76 | fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); 77 | } else { 78 | decorView.addView(createStatusBarView(activity, color, statusBarAlpha)); 79 | } 80 | setRootView(activity); 81 | } 82 | } 83 | 84 | /** 85 | * 为滑动返回界面设置状态栏颜色 86 | * 87 | * @param activity 需要设置的activity 88 | * @param color 状态栏颜色值 89 | */ 90 | public static void setColorForSwipeBack(Activity activity, int color) { 91 | setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA); 92 | } 93 | 94 | /** 95 | * 为滑动返回界面设置状态栏颜色 96 | * 97 | * @param activity 需要设置的activity 98 | * @param color 状态栏颜色值 99 | * @param statusBarAlpha 状态栏透明度 100 | */ 101 | public static void setColorForSwipeBack(Activity activity, @ColorInt int color, 102 | @IntRange(from = 0, to = 255) int statusBarAlpha) { 103 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 104 | 105 | ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content)); 106 | View rootView = contentView.getChildAt(0); 107 | int statusBarHeight = getStatusBarHeight(activity); 108 | if (rootView != null && rootView instanceof CoordinatorLayout) { 109 | final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView; 110 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 111 | coordinatorLayout.setFitsSystemWindows(false); 112 | contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); 113 | boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight; 114 | if (isNeedRequestLayout) { 115 | contentView.setPadding(0, statusBarHeight, 0, 0); 116 | coordinatorLayout.post(new Runnable() { 117 | @Override 118 | public void run() { 119 | coordinatorLayout.requestLayout(); 120 | } 121 | }); 122 | } 123 | } else { 124 | coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha)); 125 | } 126 | } else { 127 | contentView.setPadding(0, statusBarHeight, 0, 0); 128 | contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); 129 | } 130 | setTransparentForWindow(activity); 131 | } 132 | } 133 | 134 | /** 135 | * 设置状态栏纯色 不加半透明效果 136 | * 137 | * @param activity 需要设置的 activity 138 | * @param color 状态栏颜色值 139 | */ 140 | public static void setColorNoTranslucent(Activity activity, @ColorInt int color) { 141 | setColor(activity, color, 0); 142 | } 143 | 144 | /** 145 | * 设置状态栏颜色(5.0以下无半透明效果,不建议使用) 146 | * 147 | * @param activity 需要设置的 activity 148 | * @param color 状态栏颜色值 149 | */ 150 | @Deprecated 151 | public static void setColorDiff(Activity activity, @ColorInt int color) { 152 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 153 | return; 154 | } 155 | transparentStatusBar(activity); 156 | ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content); 157 | // 移除半透明矩形,以免叠加 158 | View fakeStatusBarView = contentView.findViewById(FAKE_STATUS_BAR_VIEW_ID); 159 | if (fakeStatusBarView != null) { 160 | if (fakeStatusBarView.getVisibility() == View.GONE) { 161 | fakeStatusBarView.setVisibility(View.VISIBLE); 162 | } 163 | fakeStatusBarView.setBackgroundColor(color); 164 | } else { 165 | contentView.addView(createStatusBarView(activity, color)); 166 | } 167 | setRootView(activity); 168 | } 169 | 170 | /** 171 | * 使状态栏半透明 172 | *

173 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏 174 | * 175 | * @param activity 需要设置的activity 176 | */ 177 | public static void setTranslucent(Activity activity) { 178 | setTranslucent(activity, DEFAULT_STATUS_BAR_ALPHA); 179 | } 180 | 181 | /** 182 | * 使状态栏半透明 183 | *

184 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏 185 | * 186 | * @param activity 需要设置的activity 187 | * @param statusBarAlpha 状态栏透明度 188 | */ 189 | public static void setTranslucent(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) { 190 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 191 | return; 192 | } 193 | setTransparent(activity); 194 | addTranslucentView(activity, statusBarAlpha); 195 | } 196 | 197 | /** 198 | * 针对根布局是 CoordinatorLayout, 使状态栏半透明 199 | *

200 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏 201 | * 202 | * @param activity 需要设置的activity 203 | * @param statusBarAlpha 状态栏透明度 204 | */ 205 | public static void setTranslucentForCoordinatorLayout(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) { 206 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 207 | return; 208 | } 209 | transparentStatusBar(activity); 210 | addTranslucentView(activity, statusBarAlpha); 211 | } 212 | 213 | /** 214 | * 设置状态栏全透明 215 | * 216 | * @param activity 需要设置的activity 217 | */ 218 | public static void setTransparent(Activity activity) { 219 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 220 | return; 221 | } 222 | transparentStatusBar(activity); 223 | setRootView(activity); 224 | } 225 | 226 | /** 227 | * 使状态栏透明(5.0以上半透明效果,不建议使用) 228 | *

229 | * 适用于图片作为背景的界面,此时需要图片填充到状态栏 230 | * 231 | * @param activity 需要设置的activity 232 | */ 233 | @Deprecated 234 | public static void setTranslucentDiff(Activity activity) { 235 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 236 | // 设置状态栏透明 237 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 238 | setRootView(activity); 239 | } 240 | } 241 | 242 | /** 243 | * 为DrawerLayout 布局设置状态栏变色 244 | * 245 | * @param activity 需要设置的activity 246 | * @param drawerLayout DrawerLayout 247 | * @param color 状态栏颜色值 248 | */ 249 | public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) { 250 | setColorForDrawerLayout(activity, drawerLayout, color, DEFAULT_STATUS_BAR_ALPHA); 251 | } 252 | 253 | /** 254 | * 为DrawerLayout 布局设置状态栏颜色,纯色 255 | * 256 | * @param activity 需要设置的activity 257 | * @param drawerLayout DrawerLayout 258 | * @param color 状态栏颜色值 259 | */ 260 | public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) { 261 | setColorForDrawerLayout(activity, drawerLayout, color, 0); 262 | } 263 | 264 | /** 265 | * 为DrawerLayout 布局设置状态栏变色 266 | * 267 | * @param activity 需要设置的activity 268 | * @param drawerLayout DrawerLayout 269 | * @param color 状态栏颜色值 270 | * @param statusBarAlpha 状态栏透明度 271 | */ 272 | public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color, 273 | @IntRange(from = 0, to = 255) int statusBarAlpha) { 274 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 275 | return; 276 | } 277 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 278 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 279 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 280 | activity.getWindow().setStatusBarColor(Color.TRANSPARENT); 281 | } else { 282 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 283 | } 284 | // 生成一个状态栏大小的矩形 285 | // 添加 statusBarView 到布局中 286 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0); 287 | View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID); 288 | if (fakeStatusBarView != null) { 289 | if (fakeStatusBarView.getVisibility() == View.GONE) { 290 | fakeStatusBarView.setVisibility(View.VISIBLE); 291 | } 292 | fakeStatusBarView.setBackgroundColor(color); 293 | } else { 294 | contentLayout.addView(createStatusBarView(activity, color), 0); 295 | } 296 | // 内容布局不是 LinearLayout 时,设置padding top 297 | if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) { 298 | contentLayout.getChildAt(1) 299 | .setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(), 300 | contentLayout.getPaddingRight(), contentLayout.getPaddingBottom()); 301 | } 302 | // 设置属性 303 | setDrawerLayoutProperty(drawerLayout, contentLayout); 304 | addTranslucentView(activity, statusBarAlpha); 305 | } 306 | 307 | /** 308 | * 设置 DrawerLayout 属性 309 | * 310 | * @param drawerLayout DrawerLayout 311 | * @param drawerLayoutContentLayout DrawerLayout 的内容布局 312 | */ 313 | private static void setDrawerLayoutProperty(DrawerLayout drawerLayout, ViewGroup drawerLayoutContentLayout) { 314 | ViewGroup drawer = (ViewGroup) drawerLayout.getChildAt(1); 315 | drawerLayout.setFitsSystemWindows(false); 316 | drawerLayoutContentLayout.setFitsSystemWindows(false); 317 | drawerLayoutContentLayout.setClipToPadding(true); 318 | drawer.setFitsSystemWindows(false); 319 | } 320 | 321 | /** 322 | * 为DrawerLayout 布局设置状态栏变色(5.0以下无半透明效果,不建议使用) 323 | * 324 | * @param activity 需要设置的activity 325 | * @param drawerLayout DrawerLayout 326 | * @param color 状态栏颜色值 327 | */ 328 | @Deprecated 329 | public static void setColorForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) { 330 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 331 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 332 | // 生成一个状态栏大小的矩形 333 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0); 334 | View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID); 335 | if (fakeStatusBarView != null) { 336 | if (fakeStatusBarView.getVisibility() == View.GONE) { 337 | fakeStatusBarView.setVisibility(View.VISIBLE); 338 | } 339 | fakeStatusBarView.setBackgroundColor(calculateStatusColor(color, DEFAULT_STATUS_BAR_ALPHA)); 340 | } else { 341 | // 添加 statusBarView 到布局中 342 | contentLayout.addView(createStatusBarView(activity, color), 0); 343 | } 344 | // 内容布局不是 LinearLayout 时,设置padding top 345 | if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) { 346 | contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0); 347 | } 348 | // 设置属性 349 | setDrawerLayoutProperty(drawerLayout, contentLayout); 350 | } 351 | } 352 | 353 | /** 354 | * 为 DrawerLayout 布局设置状态栏透明 355 | * 356 | * @param activity 需要设置的activity 357 | * @param drawerLayout DrawerLayout 358 | */ 359 | public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) { 360 | setTranslucentForDrawerLayout(activity, drawerLayout, DEFAULT_STATUS_BAR_ALPHA); 361 | } 362 | 363 | /** 364 | * 为 DrawerLayout 布局设置状态栏透明 365 | * 366 | * @param activity 需要设置的activity 367 | * @param drawerLayout DrawerLayout 368 | */ 369 | public static void setTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, 370 | @IntRange(from = 0, to = 255) int statusBarAlpha) { 371 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 372 | return; 373 | } 374 | setTransparentForDrawerLayout(activity, drawerLayout); 375 | addTranslucentView(activity, statusBarAlpha); 376 | } 377 | 378 | /** 379 | * 为 DrawerLayout 布局设置状态栏透明 380 | * 381 | * @param activity 需要设置的activity 382 | * @param drawerLayout DrawerLayout 383 | */ 384 | public static void setTransparentForDrawerLayout(Activity activity, DrawerLayout drawerLayout) { 385 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 386 | return; 387 | } 388 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 389 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 390 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 391 | activity.getWindow().setStatusBarColor(Color.TRANSPARENT); 392 | } else { 393 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 394 | } 395 | 396 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0); 397 | // 内容布局不是 LinearLayout 时,设置padding top 398 | if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) { 399 | contentLayout.getChildAt(1).setPadding(0, getStatusBarHeight(activity), 0, 0); 400 | } 401 | 402 | // 设置属性 403 | setDrawerLayoutProperty(drawerLayout, contentLayout); 404 | } 405 | 406 | /** 407 | * 为 DrawerLayout 布局设置状态栏透明(5.0以上半透明效果,不建议使用) 408 | * 409 | * @param activity 需要设置的activity 410 | * @param drawerLayout DrawerLayout 411 | */ 412 | @Deprecated 413 | public static void setTranslucentForDrawerLayoutDiff(Activity activity, DrawerLayout drawerLayout) { 414 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 415 | // 设置状态栏透明 416 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 417 | // 设置内容布局属性 418 | ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0); 419 | contentLayout.setFitsSystemWindows(true); 420 | contentLayout.setClipToPadding(true); 421 | // 设置抽屉布局属性 422 | ViewGroup vg = (ViewGroup) drawerLayout.getChildAt(1); 423 | vg.setFitsSystemWindows(false); 424 | // 设置 DrawerLayout 属性 425 | drawerLayout.setFitsSystemWindows(false); 426 | } 427 | } 428 | 429 | /** 430 | * 为头部是 ImageView 的界面设置状态栏全透明 431 | * 432 | * @param activity 需要设置的activity 433 | * @param needOffsetView 需要向下偏移的 View 434 | */ 435 | public static void setTransparentForImageView(Activity activity, View needOffsetView) { 436 | setTranslucentForImageView(activity, 0, needOffsetView); 437 | } 438 | 439 | /** 440 | * 为头部是 ImageView 的界面设置状态栏透明(使用默认透明度) 441 | * 442 | * @param activity 需要设置的activity 443 | * @param needOffsetView 需要向下偏移的 View 444 | */ 445 | public static void setTranslucentForImageView(Activity activity, View needOffsetView) { 446 | setTranslucentForImageView(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView); 447 | } 448 | 449 | /** 450 | * 为头部是 ImageView 的界面设置状态栏透明 451 | * 452 | * @param activity 需要设置的activity 453 | * @param statusBarAlpha 状态栏透明度 454 | * @param needOffsetView 需要向下偏移的 View 455 | */ 456 | public static void setTranslucentForImageView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha, 457 | View needOffsetView) { 458 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { 459 | return; 460 | } 461 | setTransparentForWindow(activity); 462 | addTranslucentView(activity, statusBarAlpha); 463 | if (needOffsetView != null) { 464 | Object haveSetOffset = needOffsetView.getTag(TAG_KEY_HAVE_SET_OFFSET); 465 | if (haveSetOffset != null && (Boolean) haveSetOffset) { 466 | return; 467 | } 468 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) needOffsetView.getLayoutParams(); 469 | layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin + getStatusBarHeight(activity), 470 | layoutParams.rightMargin, layoutParams.bottomMargin); 471 | needOffsetView.setTag(TAG_KEY_HAVE_SET_OFFSET, true); 472 | } 473 | } 474 | 475 | /** 476 | * 为 fragment 头部是 ImageView 的设置状态栏透明 477 | * 478 | * @param activity fragment 对应的 activity 479 | * @param needOffsetView 需要向下偏移的 View 480 | */ 481 | public static void setTranslucentForImageViewInFragment(Activity activity, View needOffsetView) { 482 | setTranslucentForImageViewInFragment(activity, DEFAULT_STATUS_BAR_ALPHA, needOffsetView); 483 | } 484 | 485 | /** 486 | * 为 fragment 头部是 ImageView 的设置状态栏透明 487 | * 488 | * @param activity fragment 对应的 activity 489 | * @param needOffsetView 需要向下偏移的 View 490 | */ 491 | public static void setTransparentForImageViewInFragment(Activity activity, View needOffsetView) { 492 | setTranslucentForImageViewInFragment(activity, 0, needOffsetView); 493 | } 494 | 495 | /** 496 | * 为 fragment 头部是 ImageView 的设置状态栏透明 497 | * 498 | * @param activity fragment 对应的 activity 499 | * @param statusBarAlpha 状态栏透明度 500 | * @param needOffsetView 需要向下偏移的 View 501 | */ 502 | public static void setTranslucentForImageViewInFragment(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha, 503 | View needOffsetView) { 504 | setTranslucentForImageView(activity, statusBarAlpha, needOffsetView); 505 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 506 | clearPreviousSetting(activity); 507 | } 508 | } 509 | 510 | /** 511 | * 隐藏伪状态栏 View 512 | * 513 | * @param activity 调用的 Activity 514 | */ 515 | public static void hideFakeStatusBarView(Activity activity) { 516 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); 517 | View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID); 518 | if (fakeStatusBarView != null) { 519 | fakeStatusBarView.setVisibility(View.GONE); 520 | } 521 | View fakeTranslucentView = decorView.findViewById(FAKE_TRANSLUCENT_VIEW_ID); 522 | if (fakeTranslucentView != null) { 523 | fakeTranslucentView.setVisibility(View.GONE); 524 | } 525 | } 526 | 527 | @TargetApi(Build.VERSION_CODES.M) 528 | public static void setLightMode(Activity activity) { 529 | setMIUIStatusBarDarkIcon(activity, true); 530 | setMeizuStatusBarDarkIcon(activity, true); 531 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 532 | activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 533 | } 534 | } 535 | 536 | @TargetApi(Build.VERSION_CODES.M) 537 | public static void setDarkMode(Activity activity) { 538 | setMIUIStatusBarDarkIcon(activity, false); 539 | setMeizuStatusBarDarkIcon(activity, false); 540 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 541 | activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 542 | } 543 | } 544 | 545 | /** 546 | * 修改 MIUI V6 以上状态栏颜色 547 | */ 548 | private static void setMIUIStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) { 549 | Class clazz = activity.getWindow().getClass(); 550 | try { 551 | Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); 552 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); 553 | int darkModeFlag = field.getInt(layoutParams); 554 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class); 555 | extraFlagField.invoke(activity.getWindow(), darkIcon ? darkModeFlag : 0, darkModeFlag); 556 | } catch (Exception e) { 557 | //e.printStackTrace(); 558 | } 559 | } 560 | 561 | /** 562 | * 修改魅族状态栏字体颜色 Flyme 4.0 563 | */ 564 | private static void setMeizuStatusBarDarkIcon(@NonNull Activity activity, boolean darkIcon) { 565 | try { 566 | WindowManager.LayoutParams lp = activity.getWindow().getAttributes(); 567 | Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON"); 568 | Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags"); 569 | darkFlag.setAccessible(true); 570 | meizuFlags.setAccessible(true); 571 | int bit = darkFlag.getInt(null); 572 | int value = meizuFlags.getInt(lp); 573 | if (darkIcon) { 574 | value |= bit; 575 | } else { 576 | value &= ~bit; 577 | } 578 | meizuFlags.setInt(lp, value); 579 | activity.getWindow().setAttributes(lp); 580 | } catch (Exception e) { 581 | //e.printStackTrace(); 582 | } 583 | } 584 | 585 | /////////////////////////////////////////////////////////////////////////////////// 586 | 587 | @TargetApi(Build.VERSION_CODES.KITKAT) 588 | private static void clearPreviousSetting(Activity activity) { 589 | ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); 590 | View fakeStatusBarView = decorView.findViewById(FAKE_STATUS_BAR_VIEW_ID); 591 | if (fakeStatusBarView != null) { 592 | decorView.removeView(fakeStatusBarView); 593 | ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); 594 | rootView.setPadding(0, 0, 0, 0); 595 | } 596 | } 597 | 598 | /** 599 | * 添加半透明矩形条 600 | * 601 | * @param activity 需要设置的 activity 602 | * @param statusBarAlpha 透明值 603 | */ 604 | private static void addTranslucentView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) { 605 | ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content); 606 | View fakeTranslucentView = contentView.findViewById(FAKE_TRANSLUCENT_VIEW_ID); 607 | if (fakeTranslucentView != null) { 608 | if (fakeTranslucentView.getVisibility() == View.GONE) { 609 | fakeTranslucentView.setVisibility(View.VISIBLE); 610 | } 611 | fakeTranslucentView.setBackgroundColor(Color.argb(statusBarAlpha, 0, 0, 0)); 612 | } else { 613 | contentView.addView(createTranslucentStatusBarView(activity, statusBarAlpha)); 614 | } 615 | } 616 | 617 | /** 618 | * 生成一个和状态栏大小相同的彩色矩形条 619 | * 620 | * @param activity 需要设置的 activity 621 | * @param color 状态栏颜色值 622 | * @return 状态栏矩形条 623 | */ 624 | private static View createStatusBarView(Activity activity, @ColorInt int color) { 625 | return createStatusBarView(activity, color, 0); 626 | } 627 | 628 | /** 629 | * 生成一个和状态栏大小相同的半透明矩形条 630 | * 631 | * @param activity 需要设置的activity 632 | * @param color 状态栏颜色值 633 | * @param alpha 透明值 634 | * @return 状态栏矩形条 635 | */ 636 | private static View createStatusBarView(Activity activity, @ColorInt int color, int alpha) { 637 | // 绘制一个和状态栏一样高的矩形 638 | View statusBarView = new View(activity); 639 | LinearLayout.LayoutParams params = 640 | new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); 641 | statusBarView.setLayoutParams(params); 642 | statusBarView.setBackgroundColor(calculateStatusColor(color, alpha)); 643 | statusBarView.setId(FAKE_STATUS_BAR_VIEW_ID); 644 | return statusBarView; 645 | } 646 | 647 | /** 648 | * 设置根布局参数 649 | */ 650 | private static void setRootView(Activity activity) { 651 | ViewGroup parent = (ViewGroup) activity.findViewById(android.R.id.content); 652 | for (int i = 0, count = parent.getChildCount(); i < count; i++) { 653 | View childView = parent.getChildAt(i); 654 | if (childView instanceof ViewGroup) { 655 | childView.setFitsSystemWindows(true); 656 | ((ViewGroup) childView).setClipToPadding(true); 657 | } 658 | } 659 | } 660 | 661 | /** 662 | * 设置透明 663 | */ 664 | private static void setTransparentForWindow(Activity activity) { 665 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 666 | activity.getWindow().setStatusBarColor(Color.TRANSPARENT); 667 | activity.getWindow() 668 | .getDecorView() 669 | .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 670 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 671 | activity.getWindow() 672 | .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 673 | } 674 | } 675 | 676 | /** 677 | * 使状态栏透明 678 | */ 679 | @TargetApi(Build.VERSION_CODES.KITKAT) 680 | private static void transparentStatusBar(Activity activity) { 681 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 682 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 683 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 684 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); 685 | activity.getWindow().setStatusBarColor(Color.TRANSPARENT); 686 | } else { 687 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 688 | } 689 | } 690 | 691 | /** 692 | * 创建半透明矩形 View 693 | * 694 | * @param alpha 透明值 695 | * @return 半透明 View 696 | */ 697 | private static View createTranslucentStatusBarView(Activity activity, int alpha) { 698 | // 绘制一个和状态栏一样高的矩形 699 | View statusBarView = new View(activity); 700 | LinearLayout.LayoutParams params = 701 | new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); 702 | statusBarView.setLayoutParams(params); 703 | statusBarView.setBackgroundColor(Color.argb(alpha, 0, 0, 0)); 704 | statusBarView.setId(FAKE_TRANSLUCENT_VIEW_ID); 705 | return statusBarView; 706 | } 707 | 708 | /** 709 | * 获取状态栏高度 710 | * 711 | * @param context context 712 | * @return 状态栏高度 713 | */ 714 | public static int getStatusBarHeight(Context context) { 715 | // 获得状态栏高度 716 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); 717 | return context.getResources().getDimensionPixelSize(resourceId); 718 | } 719 | 720 | /** 721 | * 计算状态栏颜色 722 | * 723 | * @param color color值 724 | * @param alpha alpha值 725 | * @return 最终的状态栏颜色 726 | */ 727 | private static int calculateStatusColor(@ColorInt int color, int alpha) { 728 | if (alpha == 0) { 729 | return color; 730 | } 731 | float a = 1 - alpha / 255f; 732 | int red = color >> 16 & 0xff; 733 | int green = color >> 8 & 0xff; 734 | int blue = color & 0xff; 735 | red = (int) (red * a + 0.5); 736 | green = (int) (green * a + 0.5); 737 | blue = (int) (blue * a + 0.5); 738 | return 0xff << 24 | red << 16 | green << 8 | blue; 739 | } 740 | 741 | 742 | /** 743 | * 为布局文件中新增的状态栏布局设置背景色和高度 744 | */ 745 | public static void setStatusViewAttr(View view, Activity activity, int color) { 746 | if (view == null || activity == null) { 747 | return; 748 | } 749 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 750 | ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); 751 | layoutParams.height = StatusBarUtil.getStatusBarHeight(activity); 752 | view.setLayoutParams(layoutParams); 753 | if (color == -1) { 754 | view.setBackgroundColor(activity.getResources().getColor(R.color.colorAccent)); 755 | } else { 756 | view.setBackgroundColor(color); 757 | } 758 | 759 | } 760 | } 761 | 762 | 763 | /** 764 | * 为布局文件中新增的状态栏布局设置背景色和高度 765 | */ 766 | public static void setStatusViewAttr(View view, Activity activity) { 767 | if (view == null || activity == null) { 768 | return; 769 | } 770 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 771 | ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); 772 | layoutParams.height = StatusBarUtil.getStatusBarHeight(activity); 773 | view.setLayoutParams(layoutParams); 774 | } 775 | } 776 | 777 | /** 778 | * 增加View的paddingTop,增加的值为状态栏高度 (智能判断,并设置高度) 779 | */ 780 | public static void setPaddingSmart(Context context, View view) { 781 | if (Build.VERSION.SDK_INT >= 19) { 782 | ViewGroup.LayoutParams lp = view.getLayoutParams(); 783 | if (lp != null && lp.height > 0) { 784 | lp.height += getStatusBarHeight(context);//增高 785 | } 786 | view.setPadding(view.getPaddingLeft(), view.getPaddingTop() + getStatusBarHeight(context), 787 | view.getPaddingRight(), view.getPaddingBottom()); 788 | } 789 | } 790 | 791 | } 792 | --------------------------------------------------------------------------------