├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wkz │ │ └── hover │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wkz │ │ │ └── hover │ │ │ ├── MainActivity.java │ │ │ ├── StatusBarTools.java │ │ │ ├── TabPagerAdapter.java │ │ │ ├── TestFragment.java │ │ │ └── immersionbar │ │ │ ├── BarConfig.java │ │ │ ├── BarHide.java │ │ │ ├── BarParams.java │ │ │ ├── BarType.java │ │ │ ├── ImmersionBar.java │ │ │ ├── ImmersionFragment.java │ │ │ ├── KeyboardPatch.java │ │ │ └── OSUtils.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_arrow_left.xml │ │ ├── ic_launcher_background.xml │ │ └── ic_more.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_test.xml │ │ └── item_recycler.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── pic_image.webp │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── wkz │ └── hover │ └── ExampleUnitTest.java ├── build.gradle ├── config └── config.gradle ├── gradle.properties ├── preview └── hover.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | /gradle 15 | /gradlew 16 | /gradlew.bat 17 | /HoverToolbarTabLayout.iml 18 | /.gradle 19 | /.idea 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HoverToolbarTabLayout 2 | CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout+Toolbar+TabLayout+ViewPager,悬停Toolbar以及Tab栏 3 | -------------------------------------------------------- 4 | 5 | ![图片预览](https://github.com/FPhoenixCorneaE/HoverToolbarTabLayout/blob/master/preview/hover.gif) 6 | 7 | ----------------------------- 8 | 9 | xml中layout代码 10 | ---------- 11 | ```java 12 | 13 | 18 | 19 | 24 | 25 | 29 | 30 | 33 | 34 | 42 | 43 | 52 | 53 | 63 | 64 | 78 | 79 | 80 | 89 | 90 | 94 | 95 | 104 | 105 | 115 | 116 | 126 | 127 | 128 | 129 | 130 | 131 | 136 | 137 | 146 | 147 | 151 | 152 | 153 | ``` 154 | ----------------------------------- 155 | 156 | 顶部延伸至状态栏 157 | ------------------------- 158 | ```java 159 | ImmersionBar.with(this) 160 | .hideBar(BarHide.FLAG_SHOW_BAR) 161 | .init(); 162 | 163 | int statusHeight = StatusBarTools.getStatusBarHeight(this); 164 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { 165 | CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) mTbToolbar.getLayoutParams(); 166 | lp.topMargin = statusHeight; 167 | mTbToolbar.setLayoutParams(lp); 168 | } 169 | ``` 170 | 171 | 标题栏背景色、状态栏颜色渐变 172 | ------------------ 173 | ```java 174 | mAblAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { 175 | @Override 176 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { 177 | float alpha = Math.abs(verticalOffset) * 1.0F / (mAblAppBar.getHeight() - mTbToolbar.getHeight() - StatusBarTools.getStatusBarHeight(MainActivity.this)); 178 | setToolbarBackgroundColor(alpha); 179 | setStatusBarColor(alpha); 180 | } 181 | }); 182 | ``` 183 | ```java 184 | private void setStatusBarColor(float alpha) { 185 | ImmersionBar.with(this) 186 | .statusBarColor(getGradientOverlayColor(ContextCompat.getColor(MainActivity.this, R.color.colorPrimaryDark), alpha > 1 ? 1 : alpha)) 187 | .init(); 188 | } 189 | ``` 190 | ```java 191 | private void setToolbarBackgroundColor(float alpha) { 192 | mTbToolbar.setBackgroundColor(getGradientOverlayColor(ContextCompat.getColor(this, R.color.colorPrimary), alpha > 1 ? 1 : alpha)); 193 | } 194 | ``` 195 | ```java 196 | /** 197 | * 获取渐变颜色 198 | * 199 | * @param color 原始颜色 200 | * @param fraction 透明度比率 201 | * @return 渐变颜色 202 | */ 203 | private int getGradientOverlayColor(int color, float fraction) { 204 | int red = Color.red(color); 205 | int green = Color.green(color); 206 | int blue = Color.blue(color); 207 | int alpha = (int) (Color.alpha(color) * fraction); 208 | return Color.argb(alpha, red, green, blue); 209 | } 210 | ``` 211 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.ext.android.compileSdkVersion 5 | buildToolsVersion rootProject.ext.android.buildToolsVersion 6 | 7 | defaultConfig { 8 | applicationId "com.wkz.hover" 9 | minSdkVersion rootProject.ext.android.minSdkVersion 10 | targetSdkVersion rootProject.ext.android.targetSdkVersion 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(dir: 'libs', include: ['*.jar']) 24 | implementation rootProject.ext.supportLibs 25 | } 26 | -------------------------------------------------------------------------------- /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/wkz/hover/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.wkz.hover", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover; 2 | 3 | import android.graphics.Color; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.design.widget.AppBarLayout; 7 | import android.support.design.widget.CollapsingToolbarLayout; 8 | import android.support.design.widget.TabLayout; 9 | import android.support.v4.app.Fragment; 10 | import android.support.v4.content.ContextCompat; 11 | import android.support.v4.view.ViewPager; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.support.v7.widget.Toolbar; 14 | import android.widget.ImageView; 15 | import android.widget.RelativeLayout; 16 | import android.widget.TextView; 17 | 18 | import com.wkz.hover.immersionbar.BarHide; 19 | import com.wkz.hover.immersionbar.ImmersionBar; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | public class MainActivity extends AppCompatActivity { 25 | 26 | private ImageView mIvBanner; 27 | private ImageView mIvBack; 28 | /** 29 | * 30 | */ 31 | private TextView mTvTitle; 32 | private ImageView mIvMore; 33 | private RelativeLayout mRlTitle; 34 | private AppBarLayout mAblAppBar; 35 | private TabLayout mTlTab; 36 | private ViewPager mVpPager; 37 | private Toolbar mTbToolbar; 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_main); 43 | initView(); 44 | initListener(); 45 | initData(); 46 | } 47 | 48 | private void initView() { 49 | mIvBanner = (ImageView) findViewById(R.id.ivBanner); 50 | mIvBack = (ImageView) findViewById(R.id.ivBack); 51 | mTvTitle = (TextView) findViewById(R.id.tvTitle); 52 | mIvMore = (ImageView) findViewById(R.id.ivMore); 53 | mRlTitle = (RelativeLayout) findViewById(R.id.rlTitle); 54 | mAblAppBar = (AppBarLayout) findViewById(R.id.ablAppBar); 55 | mTlTab = (TabLayout) findViewById(R.id.tlTab); 56 | mVpPager = (ViewPager) findViewById(R.id.vpPager); 57 | mTbToolbar = (Toolbar) findViewById(R.id.tbToolbar); 58 | } 59 | 60 | private void initListener() { 61 | mAblAppBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { 62 | @Override 63 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { 64 | float alpha = Math.abs(verticalOffset) * 1.0F / (mAblAppBar.getHeight() - mTbToolbar.getHeight() - StatusBarTools.getStatusBarHeight(MainActivity.this)); 65 | setToolbarBackgroundColor(alpha); 66 | setStatusBarColor(alpha); 67 | } 68 | }); 69 | } 70 | 71 | private void setStatusBarColor(float alpha) { 72 | ImmersionBar.with(this) 73 | .statusBarColor(getGradientOverlayColor(ContextCompat.getColor(MainActivity.this, R.color.colorPrimaryDark), alpha > 1 ? 1 : alpha)) 74 | .init(); 75 | } 76 | 77 | private void setToolbarBackgroundColor(float alpha) { 78 | mTbToolbar.setBackgroundColor(getGradientOverlayColor(ContextCompat.getColor(this, R.color.colorPrimary), alpha > 1 ? 1 : alpha)); 79 | } 80 | 81 | /** 82 | * 获取渐变颜色 83 | * 84 | * @param color 原始颜色 85 | * @param fraction 透明度比率 86 | * @return 渐变颜色 87 | */ 88 | private int getGradientOverlayColor(int color, float fraction) { 89 | int red = Color.red(color); 90 | int green = Color.green(color); 91 | int blue = Color.blue(color); 92 | int alpha = (int) (Color.alpha(color) * fraction); 93 | return Color.argb(alpha, red, green, blue); 94 | } 95 | 96 | private void initData() { 97 | 98 | ImmersionBar.with(this) 99 | .hideBar(BarHide.FLAG_SHOW_BAR) 100 | .init(); 101 | 102 | int statusHeight = StatusBarTools.getStatusBarHeight(this); 103 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { 104 | CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) mTbToolbar.getLayoutParams(); 105 | lp.topMargin = statusHeight; 106 | mTbToolbar.setLayoutParams(lp); 107 | } 108 | 109 | List fragments = new ArrayList(3) {{ 110 | add(new TestFragment()); 111 | add(new TestFragment()); 112 | add(new TestFragment()); 113 | }}; 114 | 115 | List fragmentTitles = new ArrayList(3) {{ 116 | add("Tab1"); 117 | add("Tab2"); 118 | add("Tab3"); 119 | }}; 120 | 121 | mVpPager.setAdapter(new TabPagerAdapter(getSupportFragmentManager(), fragments, fragmentTitles)); 122 | mTlTab.setupWithViewPager(mVpPager); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/StatusBarTools.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | 6 | public class StatusBarTools { 7 | 8 | /** 9 | * Return the height of the status bar 10 | * 11 | * @param context The context 12 | * @return Height of the status bar 13 | */ 14 | public static int getStatusBarHeight(Context context) { 15 | int statusBarHeight = 0; 16 | Resources res = context.getResources(); 17 | int resourceId = res.getIdentifier("status_bar_height", "dimen", "android"); 18 | if (resourceId > 0) { 19 | statusBarHeight = res.getDimensionPixelSize(resourceId); 20 | } 21 | return statusBarHeight; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/TabPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover; 2 | 3 | import android.support.annotation.Nullable; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentPagerAdapter; 7 | 8 | import java.util.List; 9 | 10 | public class TabPagerAdapter extends FragmentPagerAdapter { 11 | 12 | private List titles; 13 | private List fragments; 14 | 15 | public TabPagerAdapter(FragmentManager fm, List fragments, List titles) { 16 | super(fm); 17 | this.fragments = fragments; 18 | this.titles = titles; 19 | } 20 | 21 | @Override 22 | public Fragment getItem(int position) { 23 | return fragments.get(position); 24 | } 25 | 26 | @Override 27 | public int getCount() { 28 | return null != fragments ? fragments.size() : 0; 29 | } 30 | 31 | 32 | @Nullable 33 | @Override 34 | public CharSequence getPageTitle(int position) { 35 | return null != titles ? titles.get(position) : super.getPageTitle(position); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/TestFragment.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | public class TestFragment extends Fragment { 14 | 15 | private View view; 16 | private RecyclerView mRvRecycler; 17 | 18 | @Nullable 19 | @Override 20 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 21 | View view = inflater.inflate(R.layout.fragment_test, container, false); 22 | initView(view); 23 | initData(); 24 | return view; 25 | } 26 | 27 | private void initView(View view) { 28 | mRvRecycler = (RecyclerView) view.findViewById(R.id.rvRecycler); 29 | } 30 | 31 | private void initData() { 32 | mRvRecycler.setLayoutManager(new LinearLayoutManager(getContext())); 33 | mRvRecycler.setHasFixedSize(true); 34 | mRvRecycler.setAdapter(new RecyclerView.Adapter() { 35 | @NonNull 36 | @Override 37 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { 38 | View itemView = LayoutInflater.from(getContext()).inflate(R.layout.item_recycler, viewGroup, false); 39 | return new RecyclerView.ViewHolder(itemView) { 40 | }; 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) { 45 | 46 | } 47 | 48 | @Override 49 | public int getItemCount() { 50 | return 20; 51 | } 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/BarConfig.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.annotation.TargetApi; 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.res.Configuration; 8 | import android.content.res.Resources; 9 | import android.os.Build; 10 | import android.util.DisplayMetrics; 11 | import android.util.TypedValue; 12 | import android.view.ViewConfiguration; 13 | 14 | import java.lang.reflect.Method; 15 | 16 | /** 17 | * Created by geyifeng on 2017/5/11. 18 | */ 19 | 20 | class BarConfig { 21 | 22 | private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; 23 | private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"; 24 | private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"; 25 | private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width"; 26 | private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; 27 | 28 | private static String sNavBarOverride; 29 | private final int mStatusBarHeight; 30 | private final int mActionBarHeight; 31 | private final boolean mHasNavigationBar; 32 | private final int mNavigationBarHeight; 33 | private final int mNavigationBarWidth; 34 | private final boolean mInPortrait; 35 | private final float mSmallestWidthDp; 36 | 37 | static { 38 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 39 | try { 40 | Class c = Class.forName("android.os.SystemProperties"); 41 | Method m = c.getDeclaredMethod("get", String.class); 42 | m.setAccessible(true); 43 | sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys"); 44 | } catch (Throwable e) { 45 | sNavBarOverride = null; 46 | } 47 | } 48 | } 49 | 50 | 51 | public BarConfig(Activity activity) { 52 | Resources res = activity.getResources(); 53 | mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT); 54 | mSmallestWidthDp = getSmallestWidthDp(activity); 55 | mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME); 56 | mActionBarHeight = getActionBarHeight(activity); 57 | mNavigationBarHeight = getNavigationBarHeight(activity); 58 | mNavigationBarWidth = getNavigationBarWidth(activity); 59 | mHasNavigationBar = (mNavigationBarHeight > 0); 60 | } 61 | 62 | @TargetApi(14) 63 | private int getActionBarHeight(Context context) { 64 | int result = 0; 65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 66 | TypedValue tv = new TypedValue(); 67 | context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); 68 | result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); 69 | } 70 | return result; 71 | } 72 | 73 | @TargetApi(14) 74 | private int getNavigationBarHeight(Context context) { 75 | Resources res = context.getResources(); 76 | int result = 0; 77 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 78 | if (hasNavBar(context)) { 79 | String key; 80 | if (mInPortrait) { 81 | key = NAV_BAR_HEIGHT_RES_NAME; 82 | } else { 83 | key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME; 84 | } 85 | return getInternalDimensionSize(res, key); 86 | } 87 | } 88 | return result; 89 | } 90 | 91 | @TargetApi(14) 92 | private int getNavigationBarWidth(Context context) { 93 | Resources res = context.getResources(); 94 | int result = 0; 95 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 96 | if (hasNavBar(context)) { 97 | return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME); 98 | } 99 | } 100 | return result; 101 | } 102 | 103 | @TargetApi(14) 104 | private boolean hasNavBar(Context context) { 105 | Resources res = context.getResources(); 106 | int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android"); 107 | if (resourceId != 0) { 108 | boolean hasNav = res.getBoolean(resourceId); 109 | // check override flag (see static block) 110 | if ("1".equals(sNavBarOverride)) { 111 | hasNav = false; 112 | } else if ("0".equals(sNavBarOverride)) { 113 | hasNav = true; 114 | } 115 | return hasNav; 116 | } else { // fallback 117 | return !ViewConfiguration.get(context).hasPermanentMenuKey(); 118 | } 119 | } 120 | 121 | private int getInternalDimensionSize(Resources res, String key) { 122 | int result = 0; 123 | int resourceId = res.getIdentifier(key, "dimen", "android"); 124 | if (resourceId > 0) { 125 | result = res.getDimensionPixelSize(resourceId); 126 | } 127 | return result; 128 | } 129 | 130 | @SuppressLint("NewApi") 131 | private float getSmallestWidthDp(Activity activity) { 132 | DisplayMetrics metrics = new DisplayMetrics(); 133 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 134 | activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); 135 | } else { 136 | // TODO this is not correct, but we don't really care pre-kitkat 137 | activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); 138 | } 139 | float widthDp = metrics.widthPixels / metrics.density; 140 | float heightDp = metrics.heightPixels / metrics.density; 141 | return Math.min(widthDp, heightDp); 142 | } 143 | 144 | /** 145 | * Should a navigation bar appear at the bottom of the screen in the current 146 | * device configuration? A navigation bar may appear on the right side of 147 | * the screen in certain configurations. 148 | * 149 | * @return True if navigation should appear at the bottom of the screen, False otherwise. 150 | */ 151 | public boolean isNavigationAtBottom() { 152 | return (mSmallestWidthDp >= 600 || mInPortrait); 153 | } 154 | 155 | /** 156 | * Get the height of the system status bar. 157 | * 158 | * @return The height of the status bar (in pixels). 159 | */ 160 | public int getStatusBarHeight() { 161 | return mStatusBarHeight; 162 | } 163 | 164 | /** 165 | * Get the height of the action bar. 166 | * 167 | * @return The height of the action bar (in pixels). 168 | */ 169 | public int getActionBarHeight() { 170 | return mActionBarHeight; 171 | } 172 | 173 | /** 174 | * Does this device have a system navigation bar? 175 | * 176 | * @return True if this device uses soft key navigation, False otherwise. 177 | */ 178 | public boolean hasNavigtionBar() { 179 | return mHasNavigationBar; 180 | } 181 | 182 | /** 183 | * Get the height of the system navigation bar. 184 | * 185 | * @return The height of the navigation bar (in pixels). If the device does not have 186 | * soft navigation keys, this will always return 0. 187 | */ 188 | public int getNavigationBarHeight() { 189 | return mNavigationBarHeight; 190 | } 191 | 192 | /** 193 | * Get the width of the system navigation bar when it is placed vertically on the screen. 194 | * 195 | * @return The width of the navigation bar (in pixels). If the device does not have 196 | * soft navigation keys, this will always return 0. 197 | */ 198 | public int getNavigationBarWidth() { 199 | return mNavigationBarWidth; 200 | } 201 | 202 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/BarHide.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | /** 4 | * Created by geyifeng on 2017/4/25. 5 | */ 6 | 7 | public enum BarHide { 8 | FLAG_HIDE_STATUS_BAR, //隐藏状态栏 9 | FLAG_HIDE_NAVIGATION_BAR, //隐藏导航栏 10 | FLAG_HIDE_BAR, //隐藏状态栏和导航栏 11 | FLAG_SHOW_BAR //显示状态栏和导航栏 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/BarParams.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | import android.graphics.Color; 4 | import android.support.annotation.ColorInt; 5 | import android.support.annotation.FloatRange; 6 | import android.view.View; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * Created by geyifeng on 2017/5/9. 13 | */ 14 | public class BarParams { 15 | @ColorInt 16 | public int statusBarColor = Color.TRANSPARENT; 17 | @ColorInt 18 | public int navigationBarColor = Color.BLACK; 19 | @FloatRange(from = 0f, to = 1f) 20 | public float statusBarAlpha = 0.0f; 21 | @FloatRange(from = 0f, to = 1f) 22 | public float navigationBarAlpha = 0.0f; 23 | public boolean fullScreen = false; 24 | public boolean fullScreenTemp = fullScreen; 25 | public BarHide barHide = BarHide.FLAG_SHOW_BAR; 26 | public boolean darkFont = false; 27 | @ColorInt 28 | public int statusBarColorTransform = Color.BLACK; 29 | @ColorInt 30 | public int navigationBarColorTransform = Color.BLACK; 31 | public View view; 32 | public Map> viewMap = new HashMap<>(); 33 | @ColorInt 34 | public int viewColorBeforeTransform = statusBarColor; 35 | @ColorInt 36 | public int viewColorAfterTransform = statusBarColorTransform; 37 | public boolean fits = false; 38 | public int navigationBarColorTem = navigationBarColor; 39 | public View statusBarView; 40 | public View navigationBarView; 41 | public View statusBarViewByHeight; 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/BarType.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | /** 4 | * Created by geyifeng on 2017/4/25. 5 | */ 6 | public enum BarType { 7 | STATUS_BAR, //状态栏 8 | NAVIGATION_BAR, //导航栏 9 | ALL_BAR //同时设置状态栏和导航栏 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/ImmersionBar.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.graphics.Color; 6 | import android.os.Build; 7 | import android.support.annotation.ColorRes; 8 | import android.support.annotation.FloatRange; 9 | import android.support.annotation.IntegerRes; 10 | import android.support.v4.content.ContextCompat; 11 | import android.support.v4.graphics.ColorUtils; 12 | import android.view.Gravity; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.Window; 16 | import android.view.WindowManager; 17 | import android.widget.FrameLayout; 18 | 19 | import java.lang.reflect.Field; 20 | import java.lang.reflect.Method; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | /** 26 | * android 4.4以上bar 管理 27 | * Created by gyf on 2017/05/09. 28 | */ 29 | @TargetApi(Build.VERSION_CODES.KITKAT) 30 | public class ImmersionBar { 31 | 32 | private static Map mMap = new HashMap<>(); 33 | private Activity mActivity; 34 | private Window mWindow; 35 | private ViewGroup mViewGroup; 36 | private BarParams mBarParams; 37 | private ViewGroup mContentView; 38 | 39 | private BarConfig mConfig; 40 | 41 | 42 | private ImmersionBar() { 43 | } 44 | 45 | private ImmersionBar(Activity activity) { 46 | 47 | mActivity = activity; 48 | mWindow = activity.getWindow(); 49 | mViewGroup = (ViewGroup) mWindow.getDecorView(); 50 | mContentView = (ViewGroup) mActivity.findViewById(android.R.id.content); 51 | mConfig = new BarConfig(activity); 52 | 53 | if (!mMap.isEmpty()) { 54 | if (mMap.get(mActivity.getClass().getName()) == null) { 55 | mBarParams = new BarParams(); 56 | mMap.put(mActivity.getClass().getName(), mBarParams); 57 | } else { 58 | mBarParams = mMap.get(mActivity.getClass().getName()); 59 | } 60 | } else { 61 | mBarParams = new BarParams(); 62 | mMap.put(mActivity.getClass().getName(), mBarParams); 63 | } 64 | } 65 | 66 | /** 67 | * With immersion bar. 68 | * 69 | * @param activity the activity 70 | * @return the immersion bar 71 | */ 72 | public static ImmersionBar with(Activity activity) { 73 | return new ImmersionBar(activity); 74 | } 75 | 76 | /** 77 | * 透明状态栏,默认透明 78 | * 79 | * @return the immersion bar 80 | */ 81 | public ImmersionBar transparentStatusBar() { 82 | mBarParams.statusBarColor = Color.TRANSPARENT; 83 | return this; 84 | } 85 | 86 | /** 87 | * 透明导航栏,默认黑色 88 | * 89 | * @return the immersion bar 90 | */ 91 | public ImmersionBar transparentNavigationBar() { 92 | mBarParams.navigationBarColor = Color.TRANSPARENT; 93 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 94 | mBarParams.fullScreen = true; 95 | return this; 96 | } 97 | 98 | /** 99 | * 透明状态栏和导航栏 100 | * 101 | * @return the immersion bar 102 | */ 103 | public ImmersionBar transparentBar() { 104 | mBarParams.statusBarColor = Color.TRANSPARENT; 105 | mBarParams.navigationBarColor = Color.TRANSPARENT; 106 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 107 | mBarParams.fullScreen = true; 108 | return this; 109 | } 110 | 111 | /** 112 | * 状态栏颜色 113 | * 114 | * @param statusBarColor 状态栏颜色,资源文件(R.color.xxx) 115 | * @return the immersion bar 116 | */ 117 | public ImmersionBar statusBarColorRes(@ColorRes int statusBarColor) { 118 | mBarParams.statusBarColor = ContextCompat.getColor(mActivity, statusBarColor); 119 | return this; 120 | } 121 | 122 | /** 123 | * 状态栏颜色 124 | * 125 | * @param statusBarColor 状态栏颜色 126 | * @return the immersion bar 127 | */ 128 | public ImmersionBar statusBarColor(int statusBarColor) { 129 | mBarParams.statusBarColor = statusBarColor; 130 | return this; 131 | } 132 | 133 | /** 134 | * 状态栏颜色 135 | * 136 | * @param statusBarColor 状态栏颜色,资源文件(R.color.xxx) 137 | * @param alpha the alpha 透明度 138 | * @return the immersion bar 139 | */ 140 | public ImmersionBar statusBarColor(@ColorRes int statusBarColor, 141 | @FloatRange(from = 0f, to = 1f) float alpha) { 142 | mBarParams.statusBarColor = ContextCompat.getColor(mActivity, statusBarColor); 143 | mBarParams.statusBarAlpha = alpha; 144 | return this; 145 | } 146 | 147 | /** 148 | * 状态栏颜色 149 | * 150 | * @param statusBarColor 状态栏颜色,资源文件(R.color.xxx) 151 | * @param statusBarColorTransform the status bar color transform 状态栏变换后的颜色 152 | * @param alpha the alpha 透明度 153 | * @return the immersion bar 154 | */ 155 | public ImmersionBar statusBarColor(@ColorRes int statusBarColor, 156 | @ColorRes int statusBarColorTransform, 157 | @FloatRange(from = 0f, to = 1f) float alpha) { 158 | mBarParams.statusBarColor = ContextCompat.getColor(mActivity, statusBarColor); 159 | mBarParams.statusBarColorTransform = ContextCompat.getColor(mActivity, statusBarColorTransform); 160 | mBarParams.statusBarAlpha = alpha; 161 | return this; 162 | } 163 | 164 | /** 165 | * 导航栏颜色 166 | * 167 | * @param navigationBarColor the navigation bar color 导航栏颜色 168 | * @return the immersion bar 169 | */ 170 | public ImmersionBar navigationBarColor(@ColorRes int navigationBarColor) { 171 | mBarParams.navigationBarColor = ContextCompat.getColor(mActivity, navigationBarColor); 172 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 173 | return this; 174 | } 175 | 176 | /** 177 | * 导航栏颜色 178 | * 179 | * @param navigationBarColor the navigation bar color 导航栏颜色 180 | * @param navigationAlpha the navigation alpha 透明度 181 | * @return the immersion bar 182 | */ 183 | public ImmersionBar navigationBarColor(@ColorRes int navigationBarColor, 184 | @FloatRange(from = 0f, to = 1f) float navigationAlpha) { 185 | mBarParams.navigationBarColor = ContextCompat.getColor(mActivity, navigationBarColor); 186 | mBarParams.navigationBarAlpha = navigationAlpha; 187 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 188 | return this; 189 | } 190 | 191 | /** 192 | * 导航栏颜色 193 | * 194 | * @param navigationBarColor the navigation bar color 导航栏颜色 195 | * @param navigationBarColorTransform the navigation bar color transform 导航栏变色后的颜色 196 | * @param navigationAlpha the navigation alpha 透明度 197 | * @return the immersion bar 198 | */ 199 | public ImmersionBar navigationBarColor(@ColorRes int navigationBarColor, 200 | @ColorRes int navigationBarColorTransform, 201 | @FloatRange(from = 0f, to = 1f) float navigationAlpha) { 202 | mBarParams.navigationBarColor = ContextCompat.getColor(mActivity, navigationBarColor); 203 | mBarParams.navigationBarColorTransform = ContextCompat.getColor(mActivity, navigationBarColorTransform); 204 | mBarParams.navigationBarAlpha = navigationAlpha; 205 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 206 | return this; 207 | } 208 | 209 | /** 210 | * 状态栏和导航栏颜色 211 | * 212 | * @param barColor the bar color 213 | * @return the immersion bar 214 | */ 215 | public ImmersionBar barColor(@ColorRes int barColor) { 216 | mBarParams.statusBarColor = ContextCompat.getColor(mActivity, barColor); 217 | mBarParams.navigationBarColor = ContextCompat.getColor(mActivity, barColor); 218 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 219 | return this; 220 | } 221 | 222 | /** 223 | * 状态栏和导航栏颜色 224 | * 225 | * @param barColor the bar color 226 | * @param barAlpha the bar alpha 227 | * @return the immersion bar 228 | */ 229 | public ImmersionBar barColor(@ColorRes int barColor, @FloatRange(from = 0f, to = 1f) float barAlpha) { 230 | mBarParams.statusBarColor = ContextCompat.getColor(mActivity, barColor); 231 | mBarParams.navigationBarColor = ContextCompat.getColor(mActivity, barColor); 232 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 233 | mBarParams.statusBarAlpha = barAlpha; 234 | mBarParams.navigationBarAlpha = barAlpha; 235 | return this; 236 | } 237 | 238 | /** 239 | * 状态栏和导航栏颜色 240 | * 241 | * @param barColor the bar color 242 | * @param barColorTransform the bar color transform 243 | * @param barAlpha the bar alpha 244 | * @return the immersion bar 245 | */ 246 | public ImmersionBar barColor(@ColorRes int barColor, 247 | @ColorRes int barColorTransform, 248 | @FloatRange(from = 0f, to = 1f) float barAlpha) { 249 | mBarParams.statusBarColor = ContextCompat.getColor(mActivity, barColor); 250 | mBarParams.navigationBarColor = ContextCompat.getColor(mActivity, barColor); 251 | mBarParams.navigationBarColorTem = mBarParams.navigationBarColor; 252 | 253 | mBarParams.statusBarColorTransform = ContextCompat.getColor(mActivity, barColorTransform); 254 | mBarParams.navigationBarColorTransform = ContextCompat.getColor(mActivity, barColorTransform); 255 | 256 | mBarParams.statusBarAlpha = barAlpha; 257 | mBarParams.navigationBarAlpha = barAlpha; 258 | return this; 259 | } 260 | 261 | 262 | /** 263 | * 状态栏根据透明度最后变换成的颜色 264 | * 265 | * @param statusBarColorTransform the status bar color transform 266 | * @return the immersion bar 267 | */ 268 | public ImmersionBar statusBarColorTransform(@ColorRes int statusBarColorTransform) { 269 | mBarParams.statusBarColorTransform = ContextCompat.getColor(mActivity, statusBarColorTransform); 270 | return this; 271 | } 272 | 273 | /** 274 | * 导航栏根据透明度最后变换成的颜色 275 | * 276 | * @param navigationBarColorTransform the m navigation bar color transform 277 | * @return the immersion bar 278 | */ 279 | public ImmersionBar navigationBarColorTransform(@ColorRes int navigationBarColorTransform) { 280 | mBarParams.navigationBarColorTransform = ContextCompat.getColor(mActivity, navigationBarColorTransform); 281 | return this; 282 | } 283 | 284 | /** 285 | * 状态栏和导航栏根据透明度最后变换成的颜色 286 | * 287 | * @param barColorTransform the bar color transform 288 | * @return the immersion bar 289 | */ 290 | public ImmersionBar barColorTransform(@ColorRes int barColorTransform) { 291 | mBarParams.statusBarColorTransform = ContextCompat.getColor(mActivity, barColorTransform); 292 | mBarParams.navigationBarColorTransform = ContextCompat.getColor(mActivity, barColorTransform); 293 | return this; 294 | } 295 | 296 | /** 297 | * 颜色变换支持View 298 | * 299 | * @param view the view 300 | * @return the view transform color 301 | */ 302 | public ImmersionBar setViewSupportTransformColor(View view) { 303 | mBarParams.view = view; 304 | mBarParams.viewColorBeforeTransform = mBarParams.statusBarColor; 305 | mBarParams.viewColorAfterTransform = mBarParams.statusBarColorTransform; 306 | return this; 307 | } 308 | 309 | /** 310 | * 颜色变换支持View 311 | * 312 | * @param view the view 313 | * @param viewColorAfterTransform 变换后的颜色 314 | * @return the view transform color 315 | */ 316 | public ImmersionBar setViewSupportTransformColor(View view, @ColorRes int viewColorAfterTransform) { 317 | mBarParams.view = view; 318 | mBarParams.viewColorBeforeTransform = mBarParams.statusBarColor; 319 | mBarParams.viewColorAfterTransform = ContextCompat.getColor(mActivity, viewColorAfterTransform); 320 | return this; 321 | } 322 | 323 | /** 324 | * 颜色变换支持View 325 | * 326 | * @param view the view 327 | * @param viewColorBeforeTransform 变换前的颜色 328 | * @param viewColorAfterTransform 变换后的颜色 329 | * @return the immersion bar 330 | */ 331 | public ImmersionBar setViewSupportTransformColor(View view, @ColorRes int viewColorBeforeTransform, 332 | @ColorRes int viewColorAfterTransform) { 333 | mBarParams.view = view; 334 | mBarParams.viewColorBeforeTransform = ContextCompat.getColor(mActivity, viewColorBeforeTransform); 335 | mBarParams.viewColorAfterTransform = ContextCompat.getColor(mActivity, viewColorAfterTransform); 336 | return this; 337 | } 338 | 339 | /** 340 | * Add 颜色变换支持View 341 | * 342 | * @param view the view 343 | * @return the immersion bar 344 | */ 345 | public ImmersionBar addViewSupportTransformColor(View view) { 346 | Map map = new HashMap<>(); 347 | map.put(mBarParams.statusBarColor, mBarParams.statusBarColorTransform); 348 | mBarParams.viewMap.put(view, map); 349 | return this; 350 | } 351 | 352 | /** 353 | * Add 颜色变换支持View 354 | * 355 | * @param view the view 356 | * @param viewColorAfterTransform the view color after transform 357 | * @return the immersion bar 358 | */ 359 | public ImmersionBar addViewSupportTransformColor(View view, @ColorRes int viewColorAfterTransform) { 360 | Map map = new HashMap<>(); 361 | map.put(mBarParams.statusBarColor, ContextCompat.getColor(mActivity, viewColorAfterTransform)); 362 | mBarParams.viewMap.put(view, map); 363 | return this; 364 | } 365 | 366 | /** 367 | * Add 颜色变换支持View 368 | * 369 | * @param view the view 370 | * @param viewColorBeforeTransform the view color before transform 371 | * @param viewColorAfterTransform the view color after transform 372 | * @return the immersion bar 373 | */ 374 | public ImmersionBar addViewSupportTransformColor(View view, @ColorRes int viewColorBeforeTransform, 375 | @ColorRes int viewColorAfterTransform) { 376 | Map map = new HashMap<>(); 377 | map.put(ContextCompat.getColor(mActivity, viewColorBeforeTransform), 378 | ContextCompat.getColor(mActivity, viewColorAfterTransform)); 379 | mBarParams.viewMap.put(view, map); 380 | return this; 381 | } 382 | 383 | /** 384 | * 移除view支持变身 385 | * 386 | * @return the immersion bar 387 | */ 388 | public ImmersionBar removeSupportView() { 389 | mBarParams.view = null; 390 | return this; 391 | } 392 | 393 | /** 394 | * Remove support view immersion bar. 395 | * 396 | * @param view the view 397 | * @return the immersion bar 398 | */ 399 | public ImmersionBar removeSupportView(View view) { 400 | if (view != null) { 401 | if (view == mBarParams.view) 402 | mBarParams.view = null; 403 | Map map = mBarParams.viewMap.get(view); 404 | if (map.size() != 0) { 405 | mBarParams.viewMap.remove(view); 406 | } 407 | } 408 | return this; 409 | } 410 | 411 | /** 412 | * Remove support all view immersion bar. 413 | * 414 | * @return the immersion bar 415 | */ 416 | public ImmersionBar removeSupportAllView() { 417 | if (mBarParams.viewMap.size() != 0) { 418 | mBarParams.viewMap.clear(); 419 | } 420 | return this; 421 | } 422 | 423 | /** 424 | * 有导航栏的情况下,Activity是否全屏显示 425 | * 426 | * @param isFullScreen the is full screen 427 | * @return the immersion bar 428 | */ 429 | public ImmersionBar fullScreen(boolean isFullScreen) { 430 | mBarParams.fullScreen = isFullScreen; 431 | return this; 432 | } 433 | 434 | /** 435 | * 状态栏透明度 436 | * 437 | * @param statusAlpha the status alpha 438 | * @return the immersion bar 439 | */ 440 | public ImmersionBar statusBarAlpha(@FloatRange(from = 0f, to = 1f) float statusAlpha) { 441 | mBarParams.statusBarAlpha = statusAlpha; 442 | return this; 443 | } 444 | 445 | /** 446 | * 导航栏透明度 447 | * 448 | * @param navigationAlpha the navigation alpha 449 | * @return the immersion bar 450 | */ 451 | public ImmersionBar navigationBarAlpha(@FloatRange(from = 0f, to = 1f) float navigationAlpha) { 452 | mBarParams.navigationBarAlpha = navigationAlpha; 453 | return this; 454 | } 455 | 456 | /** 457 | * 状态栏和导航栏透明度 458 | * 459 | * @param barAlpha the bar alpha 460 | * @return the immersion bar 461 | */ 462 | public ImmersionBar barAlpha(@FloatRange(from = 0f, to = 1f) float barAlpha) { 463 | mBarParams.statusBarAlpha = barAlpha; 464 | mBarParams.navigationBarAlpha = barAlpha; 465 | return this; 466 | } 467 | 468 | /** 469 | * 状态栏字体深色或亮色 470 | * 471 | * @param isDarkFont true 深色 472 | * @return the immersion bar 473 | */ 474 | public ImmersionBar statusBarDarkFont(boolean isDarkFont) { 475 | mBarParams.darkFont = isDarkFont; 476 | return this; 477 | } 478 | 479 | /** 480 | * 隐藏导航栏或状态栏 481 | * 482 | * @param barHide the bar hide 483 | * @return the immersion bar 484 | */ 485 | public ImmersionBar hideBar(BarHide barHide) { 486 | mBarParams.barHide = barHide; 487 | if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { 488 | if ((mBarParams.barHide == BarHide.FLAG_HIDE_NAVIGATION_BAR) || 489 | (mBarParams.barHide == BarHide.FLAG_HIDE_BAR)) { 490 | mBarParams.navigationBarColor = Color.TRANSPARENT; 491 | mBarParams.fullScreenTemp = true; 492 | } else { 493 | mBarParams.navigationBarColor = mBarParams.navigationBarColorTem; 494 | mBarParams.fullScreenTemp = false; 495 | } 496 | } 497 | return this; 498 | } 499 | 500 | /** 501 | * 解决布局与状态栏重叠问题 502 | * 503 | * @param fits the fits 504 | * @return the immersion bar 505 | */ 506 | public ImmersionBar fitsSystemWindows(boolean fits) { 507 | mBarParams.fits = fits; 508 | return this; 509 | } 510 | 511 | /** 512 | * 通过状态栏高度动态设置状态栏布局 513 | * 514 | * @param view the view 515 | * @return the immersion bar 516 | */ 517 | public ImmersionBar statusBarView(View view) { 518 | mBarParams.statusBarViewByHeight = view; 519 | return this; 520 | } 521 | 522 | /** 523 | * 通过状态栏高度动态设置状态栏布局,只支持在activity里设置 524 | * 525 | * @param viewId the view id 526 | * @return the immersion bar 527 | */ 528 | @SuppressWarnings("ResourceType") 529 | public ImmersionBar statusBarView(@IntegerRes int viewId) { 530 | mBarParams.statusBarViewByHeight = mActivity.findViewById(viewId); 531 | return this; 532 | } 533 | 534 | /** 535 | * 通过上面配置后初始化后方可成功调用 536 | */ 537 | public void init() { 538 | mMap.put(mActivity.getClass().getName(), mBarParams); 539 | initBar(); //初始化沉浸式 540 | setStatusBarView(); //通过状态栏高度动态设置状态栏布局 541 | fitsSystemWindows(); //解决状态栏和布局重叠问题 542 | transformView(); //变色view 543 | } 544 | 545 | /** 546 | * 当Activity关闭的时候,在onDestroy方法中调用 547 | */ 548 | public void destroy() { 549 | String key = mActivity.getClass().getName(); 550 | if (key != null) { 551 | if (mBarParams != null) { 552 | mBarParams = null; 553 | } 554 | mMap.remove(key); 555 | } 556 | } 557 | 558 | private void initBar() { 559 | int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE; //防止系统栏隐藏时内容区域大小发生变化 560 | uiFlags = hideBar(uiFlags); //隐藏状态栏或者导航栏 561 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 562 | uiFlags = setStatusBarDarkFont(uiFlags); //设置状态栏字体为暗色 563 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 564 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; //Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态栏遮住。 565 | if (mBarParams.fullScreen) { 566 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; //Activity全屏显示,但导航栏不会被隐藏覆盖,导航栏依然可见,Activity底部布局部分会被导航栏遮住。 567 | } 568 | mWindow.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS 569 | | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); //取消设置透明状态栏和导航栏 570 | mWindow.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); //需要设置这个才能设置状态栏颜色 571 | mWindow.setStatusBarColor(ColorUtils.blendARGB(mBarParams.statusBarColor, 572 | mBarParams.statusBarColorTransform, mBarParams.statusBarAlpha)); //设置状态栏颜色 573 | mWindow.setNavigationBarColor(ColorUtils.blendARGB(mBarParams.navigationBarColor, 574 | mBarParams.navigationBarColorTransform, mBarParams.navigationBarAlpha)); //设置导航栏颜色 575 | } else { 576 | mWindow.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//透明状态栏 577 | mWindow.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);//透明导航栏,设置这个,如果有导航栏,底部布局会被导航栏遮住 578 | setupStatusBarView(); //创建一个假的状态栏 579 | if (mConfig.hasNavigtionBar()) //判断是否存在导航栏 580 | setupNavBarView(); //创建一个假的导航栏 581 | 582 | // 解决android4.4有导航栏的情况下,activity底部被导航栏遮挡的问题 583 | if (mConfig.hasNavigtionBar() && !mBarParams.fullScreenTemp && !mBarParams.fullScreen) { 584 | if (mConfig.isNavigationAtBottom()) //判断导航栏是否在底部 585 | mContentView.setPadding(0, 0, 0, mConfig.getNavigationBarHeight()); //有导航栏,获得rootView的根节点,然后设置距离底部的padding值为导航栏的高度值 586 | else 587 | mContentView.setPadding(0, 0, mConfig.getNavigationBarWidth(), 0); //不在底部,设置距离右边的padding值为导航栏的宽度值 588 | } else { 589 | mContentView.setPadding(0, 0, 0, 0); //没有导航栏,什么都不做 590 | } 591 | } 592 | } 593 | mWindow.getDecorView().setSystemUiVisibility(uiFlags); 594 | } 595 | 596 | /** 597 | * Hide bar. 598 | * 隐藏或显示状态栏和导航栏。 状态栏和导航栏的颜色不起作用,都是透明色,以最后一次调用为准 599 | * 600 | * @param uiFlags the ui flags 601 | * @return the int 602 | */ 603 | private int hideBar(int uiFlags) { 604 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 605 | switch (mBarParams.barHide) { 606 | case FLAG_HIDE_BAR: 607 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 608 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 609 | | View.INVISIBLE; 610 | break; 611 | case FLAG_HIDE_STATUS_BAR: 612 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.INVISIBLE; 613 | break; 614 | case FLAG_HIDE_NAVIGATION_BAR: 615 | uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 616 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 617 | break; 618 | case FLAG_SHOW_BAR: 619 | uiFlags |= View.SYSTEM_UI_FLAG_VISIBLE; 620 | break; 621 | } 622 | } 623 | return uiFlags | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 624 | } 625 | 626 | /** 627 | * Sets status bar dark font. 628 | * 设置状态栏字体颜色,android6.0以上或者miuiv6以上或者flymeOS 629 | */ 630 | private int setStatusBarDarkFont(int uiFlags) { 631 | String MIUIVersion = OSUtils.MIUIVersion(); 632 | if (!MIUIVersion.isEmpty()) { 633 | if (Integer.valueOf(MIUIVersion.substring(1)) >= 6) { 634 | MIUISetStatusBarLightMode(); 635 | } 636 | return uiFlags; 637 | } 638 | if (OSUtils.isFlymeOS()) { 639 | flymeSetStatusBarLightMode(); 640 | return uiFlags; 641 | } 642 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mBarParams.darkFont) { 643 | return uiFlags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 644 | } else { 645 | return uiFlags | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; 646 | } 647 | } 648 | 649 | /** 650 | * 设置状态栏图标为深色和魅族特定的文字风格 651 | * 可以用来判断是否为Flyme用户 652 | * 653 | * @return boolean 成功执行返回true 654 | */ 655 | private boolean flymeSetStatusBarLightMode() { 656 | boolean result = false; 657 | if (mWindow != null) { 658 | try { 659 | WindowManager.LayoutParams lp = mWindow.getAttributes(); 660 | Field darkFlag = WindowManager.LayoutParams.class 661 | .getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON"); 662 | Field meizuFlags = WindowManager.LayoutParams.class 663 | .getDeclaredField("meizuFlags"); 664 | darkFlag.setAccessible(true); 665 | meizuFlags.setAccessible(true); 666 | int bit = darkFlag.getInt(null); 667 | int value = meizuFlags.getInt(lp); 668 | if (mBarParams.darkFont) { 669 | value |= bit; 670 | } else { 671 | value &= ~bit; 672 | } 673 | meizuFlags.setInt(lp, value); 674 | mWindow.setAttributes(lp); 675 | result = true; 676 | } catch (Exception e) { 677 | e.printStackTrace(); 678 | } 679 | } 680 | return result; 681 | } 682 | 683 | /** 684 | * 设置状态栏字体图标为深色,需要MIUIV6以上 685 | * 686 | * @return boolean 成功执行返回true 687 | */ 688 | private boolean MIUISetStatusBarLightMode() { 689 | boolean result = false; 690 | if (mWindow != null) { 691 | Class clazz = mWindow.getClass(); 692 | try { 693 | int darkModeFlag = 0; 694 | Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); 695 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); 696 | darkModeFlag = field.getInt(layoutParams); 697 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class); 698 | if (mBarParams.darkFont) { 699 | extraFlagField.invoke(mWindow, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体 700 | } else { 701 | extraFlagField.invoke(mWindow, 0, darkModeFlag);//清除黑色字体 702 | } 703 | result = true; 704 | } catch (Exception e) { 705 | e.printStackTrace(); 706 | } 707 | } 708 | return result; 709 | } 710 | 711 | /** 712 | * 变色view 713 | *

714 | * Transform view. 715 | */ 716 | private void transformView() { 717 | if (mBarParams.view != null) { 718 | mBarParams.view.setBackgroundColor(ColorUtils.blendARGB(mBarParams.viewColorBeforeTransform, 719 | mBarParams.viewColorAfterTransform, mBarParams.statusBarAlpha)); 720 | } 721 | if (mBarParams.viewMap.size() != 0) { 722 | Set>> entrySet = mBarParams.viewMap.entrySet(); 723 | for (Map.Entry> entry : entrySet) { 724 | View view = entry.getKey(); 725 | Map map = entry.getValue(); 726 | Integer colorBefore = mBarParams.statusBarColor; 727 | Integer colorAfter = mBarParams.statusBarColorTransform; 728 | for (Map.Entry integerEntry : map.entrySet()) { 729 | colorBefore = integerEntry.getKey(); 730 | colorAfter = integerEntry.getValue(); 731 | } 732 | if (view != null) 733 | view.setBackgroundColor(ColorUtils.blendARGB(colorBefore, colorAfter, mBarParams.statusBarAlpha)); 734 | 735 | } 736 | } 737 | } 738 | 739 | 740 | /** 741 | * 通过状态栏高度动态设置状态栏布局 742 | */ 743 | private void setStatusBarView() { 744 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mBarParams.statusBarViewByHeight != null) { 745 | ViewGroup.LayoutParams params = mBarParams.statusBarViewByHeight.getLayoutParams(); 746 | params.height = mConfig.getStatusBarHeight(); 747 | mBarParams.statusBarViewByHeight.setLayoutParams(params); 748 | } 749 | mBarParams.statusBarViewByHeight = null; 750 | } 751 | 752 | /** 753 | * 解决状态栏和布局重叠问题 754 | * Fits system windows. 755 | */ 756 | private void fitsSystemWindows() { 757 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 758 | if (mBarParams.fits) { 759 | mContentView.setPadding(0, getStatusBarHeight(mActivity), 0, 0); 760 | } else { 761 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 762 | mContentView.setPadding(0, 0, 0, 0); 763 | } 764 | } 765 | } 766 | 767 | /** 768 | * 设置一个可以自定义颜色的状态栏 769 | */ 770 | private void setupStatusBarView() { 771 | if (mBarParams.statusBarView == null) { 772 | mBarParams.statusBarView = new View(mActivity); 773 | } 774 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, getStatusBarHeight(mActivity)); 775 | params.gravity = Gravity.TOP; 776 | if (!isNavigationAtBottom(mActivity)) { 777 | params.rightMargin = getNavigationBarWidth(mActivity); 778 | } 779 | mBarParams.statusBarView.setLayoutParams(params); 780 | mBarParams.statusBarView.setBackgroundColor(ColorUtils.blendARGB(mBarParams.statusBarColor, 781 | mBarParams.statusBarColorTransform, mBarParams.statusBarAlpha)); 782 | mBarParams.statusBarView.setVisibility(View.VISIBLE); 783 | ViewGroup viewGroup = (ViewGroup) mBarParams.statusBarView.getParent(); 784 | if (viewGroup != null) 785 | viewGroup.removeView(mBarParams.statusBarView); 786 | mViewGroup.addView(mBarParams.statusBarView); 787 | } 788 | 789 | /** 790 | * 设置一个可以自定义颜色的导航栏 791 | */ 792 | private void setupNavBarView() { 793 | if (mBarParams.navigationBarView == null) { 794 | mBarParams.navigationBarView = new View(mActivity); 795 | } 796 | FrameLayout.LayoutParams params; 797 | if (isNavigationAtBottom(mActivity)) { 798 | params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, getNavigationBarHeight(mActivity)); 799 | params.gravity = Gravity.BOTTOM; 800 | } else { 801 | params = new FrameLayout.LayoutParams(getNavigationBarWidth(mActivity), FrameLayout.LayoutParams.MATCH_PARENT); 802 | params.gravity = Gravity.END; 803 | } 804 | mBarParams.navigationBarView.setLayoutParams(params); 805 | if (!mBarParams.fullScreen && (mBarParams.navigationBarColorTransform == Color.TRANSPARENT)) { 806 | mBarParams.navigationBarView.setBackgroundColor(ColorUtils.blendARGB(mBarParams.navigationBarColor, 807 | Color.BLACK, mBarParams.navigationBarAlpha)); 808 | } else { 809 | mBarParams.navigationBarView.setBackgroundColor(ColorUtils.blendARGB(mBarParams.navigationBarColor, 810 | mBarParams.navigationBarColorTransform, mBarParams.navigationBarAlpha)); 811 | } 812 | mBarParams.navigationBarView.setVisibility(View.VISIBLE); 813 | ViewGroup viewGroup = (ViewGroup) mBarParams.navigationBarView.getParent(); 814 | if (viewGroup != null) 815 | viewGroup.removeView(mBarParams.navigationBarView); 816 | mViewGroup.addView(mBarParams.navigationBarView); 817 | } 818 | 819 | /** 820 | * Has navigtion bar boolean. 821 | * 判断是否存在导航栏 822 | * 823 | * @param activity the activity 824 | * @return the boolean 825 | */ 826 | @TargetApi(14) 827 | public static boolean hasNavigationBar(Activity activity) { 828 | BarConfig config = new BarConfig(activity); 829 | return config.hasNavigtionBar(); 830 | } 831 | 832 | /** 833 | * Gets navigation bar height. 834 | * 获得导航栏的高度 835 | * 836 | * @param activity the activity 837 | * @return the navigation bar height 838 | */ 839 | @TargetApi(14) 840 | public static int getNavigationBarHeight(Activity activity) { 841 | BarConfig config = new BarConfig(activity); 842 | return config.getNavigationBarHeight(); 843 | } 844 | 845 | /** 846 | * Gets navigation bar width. 847 | * 获得导航栏的宽度 848 | * 849 | * @param activity the activity 850 | * @return the navigation bar width 851 | */ 852 | @TargetApi(14) 853 | public static int getNavigationBarWidth(Activity activity) { 854 | BarConfig config = new BarConfig(activity); 855 | return config.getNavigationBarWidth(); 856 | } 857 | 858 | /** 859 | * Is navigation at bottom boolean. 860 | * 判断导航栏是否在底部 861 | * 862 | * @param activity the activity 863 | * @return the boolean 864 | */ 865 | @TargetApi(14) 866 | public static boolean isNavigationAtBottom(Activity activity) { 867 | BarConfig config = new BarConfig(activity); 868 | return config.isNavigationAtBottom(); 869 | } 870 | 871 | /** 872 | * Gets status bar height. 873 | * 或得状态栏的高度 874 | * 875 | * @param activity the activity 876 | * @return the status bar height 877 | */ 878 | @TargetApi(14) 879 | public static int getStatusBarHeight(Activity activity) { 880 | BarConfig config = new BarConfig(activity); 881 | return config.getStatusBarHeight(); 882 | } 883 | 884 | /** 885 | * Gets action bar height. 886 | * 或得ActionBar得高度 887 | * 888 | * @param activity the activity 889 | * @return the action bar height 890 | */ 891 | @TargetApi(14) 892 | public static int getActionBarHeight(Activity activity) { 893 | BarConfig config = new BarConfig(activity); 894 | return config.getActionBarHeight(); 895 | } 896 | 897 | /** 898 | * Gets bar params. 899 | * 900 | * @return the bar params 901 | */ 902 | public BarParams getBarParams() { 903 | return mBarParams; 904 | } 905 | } 906 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/ImmersionFragment.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | /** 6 | * ImmersionFragment沉浸式基类,因为fragment是基于activity之上的, 7 | * 为了能够在fragment使用沉浸式而fragment之间又相互不影响,必须实现immersionInit方法, 8 | * 原理是当用户可见才执行沉浸式初始化 9 | * 10 | * Created by geyifeng on 2017/5/12. 11 | */ 12 | public abstract class ImmersionFragment extends Fragment { 13 | @Override 14 | public void setUserVisibleHint(boolean isVisibleToUser) { 15 | super.setUserVisibleHint(isVisibleToUser); 16 | if ((isVisibleToUser && isResumed())) { 17 | onResume(); 18 | } 19 | } 20 | 21 | @Override 22 | public void onResume() { 23 | super.onResume(); 24 | if (getUserVisibleHint()) { 25 | immersionInit(); 26 | } 27 | } 28 | 29 | protected abstract void immersionInit(); 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/KeyboardPatch.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Rect; 5 | import android.os.Build; 6 | import android.view.View; 7 | import android.view.ViewTreeObserver; 8 | import android.view.WindowManager; 9 | 10 | /** 11 | * 解决EditText和软键盘的问题 12 | * Created by geyifeng on 2017/5/17. 13 | */ 14 | 15 | public class KeyboardPatch { 16 | private Activity mActivity; 17 | private View mDecorView; 18 | private View mContentView; 19 | 20 | 21 | private KeyboardPatch() { 22 | } 23 | 24 | /** 25 | * 构造函数 26 | * 27 | * @param activity 需要解决bug的activity 28 | * @param contentView 界面容器,如果使用ImmersionBar这个库,对于android 5.0来说,在activity中一般是R.id.content 29 | * ,也可能是Fragment的容器,根据个人需要传递,为了方便指定布局的根节点就行 30 | */ 31 | private KeyboardPatch(Activity activity, View contentView) { 32 | this.mActivity = activity; 33 | this.mDecorView = activity.getWindow().getDecorView(); 34 | this.mContentView = contentView; 35 | } 36 | 37 | public static KeyboardPatch patch(Activity activity, View contentView) { 38 | return new KeyboardPatch(activity, contentView); 39 | } 40 | 41 | /** 42 | * 监听layout变化 43 | */ 44 | public void enable() { 45 | mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN 46 | | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); 47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 48 | mDecorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);//当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类 49 | } 50 | } 51 | 52 | /** 53 | * 取消监听 54 | */ 55 | public void disable() { 56 | mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN 57 | | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); 58 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 59 | mDecorView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener); 60 | } 61 | } 62 | 63 | private ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { 64 | @Override 65 | public void onGlobalLayout() { 66 | Rect r = new Rect(); 67 | mDecorView.getWindowVisibleDisplayFrame(r); //获取当前窗口可视区域大小的 68 | int height = mDecorView.getContext().getResources().getDisplayMetrics().heightPixels; //获取屏幕密度,不包含导航栏 69 | int diff = height - r.bottom; 70 | if (diff > 0) { 71 | if (mContentView.getPaddingBottom() != diff) { 72 | mContentView.setPadding(0, 0, 0, diff); 73 | } 74 | } else { 75 | if (mContentView.getPaddingBottom() != 0) { 76 | mContentView.setPadding(0, 0, 0, 0); 77 | } 78 | } 79 | } 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/wkz/hover/immersionbar/OSUtils.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover.immersionbar; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.lang.reflect.Method; 6 | 7 | /** 8 | * Created by geyifeng on 2017/4/18. 9 | */ 10 | 11 | public class OSUtils { 12 | 13 | private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name"; 14 | private static final String KEY_EMUI_VERSION_NAME = "ro.build.version.emui"; 15 | private static final String KEY_DISPLAY = "ro.build.display.id"; 16 | 17 | public static String MIUIVersion() { 18 | return isMIUI() ? getSystemProperty(KEY_MIUI_VERSION_NAME, null) : ""; 19 | } 20 | 21 | public static boolean isMIUI() { 22 | String property = getSystemProperty(KEY_MIUI_VERSION_NAME, null); 23 | return !TextUtils.isEmpty(property); 24 | } 25 | 26 | public static boolean isFlymeOS() { 27 | return getMeizuFlymeOSFlag().toLowerCase().contains("flyme"); 28 | } 29 | 30 | public static boolean isEMUI() { 31 | String property = getSystemProperty(KEY_EMUI_VERSION_NAME, null); 32 | return !TextUtils.isEmpty(property); 33 | } 34 | 35 | public static boolean isEMUI3_1() { 36 | if ("EmotionUI_3.1".equals(getSystemProperty(KEY_EMUI_VERSION_NAME, null))) { 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | public static String getMeizuFlymeOSFlag() { 43 | return getSystemProperty(KEY_DISPLAY, ""); 44 | } 45 | 46 | private static String getSystemProperty(String key, String defaultValue) { 47 | try { 48 | Class clz = Class.forName("android.os.SystemProperties"); 49 | Method get = clz.getMethod("get", String.class, String.class); 50 | return (String) get.invoke(clz, key, defaultValue); 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | } 54 | return defaultValue; 55 | } 56 | 57 | 58 | private static String getEmuiVersion() { 59 | Class classType; 60 | try { 61 | classType = Class.forName("android.os.SystemProperties"); 62 | Method getMethod = classType.getDeclaredMethod("get", String.class); 63 | return (String) getMethod.invoke(classType, "ro.build.version.emui"); 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | return ""; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_left.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 18 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 18 | 19 | 22 | 23 | 31 | 32 | 41 | 42 | 52 | 53 | 67 | 68 | 69 | 78 | 79 | 83 | 84 | 93 | 94 | 104 | 105 | 115 | 116 | 117 | 118 | 119 | 120 | 125 | 126 | 135 | 136 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_recycler.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/pic_image.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/app/src/main/res/mipmap-xxxhdpi/pic_image.webp -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | HoverToolbarTabLayout 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/test/java/com/wkz/hover/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.wkz.hover; 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() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply from: 'config/config.gradle' 2 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | jcenter() 8 | 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.4.1' 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | jcenter() 22 | 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /config/config.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | 3 | android = [ 4 | compileSdkVersion: 28, 5 | buildToolsVersion: "28.0.3", 6 | minSdkVersion : 17, 7 | targetSdkVersion : 28, 8 | ] 9 | 10 | dependenceVersion = [ 11 | support: "28.0.0", 12 | ] 13 | 14 | support = [ 15 | supportv4 : "com.android.support:support-v4:$dependenceVersion.support", 16 | appcompat : "com.android.support:appcompat-v7:$dependenceVersion.support", 17 | design : "com.android.support:design:$dependenceVersion.support", 18 | recyclerview: "com.android.support:recyclerview-v7:$dependenceVersion.support", 19 | cardview : "com.android.support:cardview-v7:$dependenceVersion.support", 20 | ] 21 | 22 | /*依赖这个,相当于依赖support下所有项*/ 23 | supportLibs = support.values() 24 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | #android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | #android.enableJetifier=true 20 | 21 | -------------------------------------------------------------------------------- /preview/hover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FPhoenixCorneaE/HoverToolbarTabLayout/64b75c5e9a615b740c18a8cb2ff069824cd6db2a/preview/hover.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------