├── .gitignore ├── LICENSE ├── README.md ├── art └── demo.gif ├── build.gradle ├── demo ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── amiee │ │ └── nicetab │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── me │ │ └── amiee │ │ └── nicetab │ │ └── demo │ │ ├── App.java │ │ ├── AppsAdapter.java │ │ ├── AppsFragment.java │ │ ├── DemoApplication.java │ │ ├── DemoFragment.java │ │ ├── DividerItemDecoration.java │ │ └── MainActivity.java │ └── res │ ├── drawable-hdpi │ ├── ic_activity_a.png │ ├── ic_activity_default.png │ ├── ic_activity_selected.png │ ├── ic_arrow_back.png │ ├── ic_coffee_a.png │ ├── ic_coffee_default.png │ ├── ic_coffee_selected.png │ ├── ic_github.png │ ├── ic_home_a.png │ ├── ic_home_default.png │ ├── ic_home_selected.png │ ├── ic_me_a.png │ ├── ic_me_default.png │ ├── ic_me_selected.png │ ├── ic_search_a.png │ ├── ic_search_default.png │ └── ic_search_selected.png │ ├── drawable-mdpi │ ├── ic_activity_a.png │ ├── ic_activity_default.png │ ├── ic_activity_selected.png │ ├── ic_arrow_back.png │ ├── ic_coffee_a.png │ ├── ic_coffee_default.png │ ├── ic_coffee_selected.png │ ├── ic_github.png │ ├── ic_home_a.png │ ├── ic_home_default.png │ ├── ic_home_selected.png │ ├── ic_me_a.png │ ├── ic_me_default.png │ ├── ic_me_selected.png │ ├── ic_search_a.png │ ├── ic_search_default.png │ └── ic_search_selected.png │ ├── drawable-xhdpi │ ├── ic_activity_a.png │ ├── ic_activity_default.png │ ├── ic_activity_selected.png │ ├── ic_arrow_back.png │ ├── ic_coffee_a.png │ ├── ic_coffee_default.png │ ├── ic_coffee_selected.png │ ├── ic_github.png │ ├── ic_home_a.png │ ├── ic_home_default.png │ ├── ic_home_selected.png │ ├── ic_me_a.png │ ├── ic_me_default.png │ ├── ic_me_selected.png │ ├── ic_search_a.png │ ├── ic_search_default.png │ └── ic_search_selected.png │ ├── drawable-xxhdpi │ ├── bg_badge.png │ ├── ic_activity_a.png │ ├── ic_activity_default.png │ ├── ic_activity_selected.png │ ├── ic_arrow_back.png │ ├── ic_coffee_a.png │ ├── ic_coffee_default.png │ ├── ic_coffee_selected.png │ ├── ic_github.png │ ├── ic_home_a.png │ ├── ic_home_default.png │ ├── ic_home_selected.png │ ├── ic_me_a.png │ ├── ic_me_default.png │ ├── ic_me_selected.png │ ├── ic_search_a.png │ ├── ic_search_default.png │ └── ic_search_selected.png │ ├── drawable │ ├── ic_activity.xml │ ├── ic_coffee.xml │ ├── ic_home.xml │ ├── ic_me.xml │ └── ic_search.xml │ ├── layout │ ├── activity_main.xml │ ├── custom_tab.xml │ ├── fragment_apps.xml │ ├── fragment_demo.xml │ ├── fragment_demos.xml │ ├── layout_basic.xml │ ├── list_item_app.xml │ └── list_item_demo.xml │ ├── menu │ ├── demo.xml │ ├── demo_bottom.xml │ └── main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-land │ └── dimens.xml │ ├── values-zh │ └── strings.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── me │ │ └── amiee │ │ └── nicetab │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── me │ │ └── amiee │ │ └── nicetab │ │ ├── Badge.java │ │ ├── ColorUtils.java │ │ ├── CrossFadeDrawable.java │ │ ├── NiceTabLayout.java │ │ ├── NiceTabStrip.java │ │ └── StateListDrawableHelper.java │ └── res │ └── values │ └── attrs.xml ├── maven_push.gradle └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | #Android generated 2 | bin 3 | gen 4 | gen* 5 | 6 | #Eclipse 7 | .project 8 | .classpath 9 | .settings 10 | 11 | #IntelliJ IDEA 12 | .idea 13 | *.iml 14 | *.ipr 15 | *.iws 16 | out 17 | 18 | #Maven 19 | target 20 | release.properties 21 | pom.xml.* 22 | 23 | #Ant 24 | build.xml 25 | local.properties 26 | proguard.cfg 27 | 28 | #Gradle 29 | .gradle 30 | build 31 | 32 | #OSX 33 | .DS_Store 34 | 35 | #Personal Files 36 | signing.properties -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Amiee Robot 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-NiceTab 2 | A nice tab to navigate between the different pages of a ViewPager, supports badge, blur, and cross fade effect. 3 | 4 | ![NiceTab Demo Gif](https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/master/art/demo.gif) 5 | 6 | # Usage 7 | 8 | *For a working implementation of this project see the `demo/` folder.* 9 | 10 | 1. Add the library as a project. or just 11 | 12 | ```groovy 13 | dependencies { 14 | compile 'me.amiee:nicetab:1.0.0' 15 | } 16 | ```` 17 | 18 | 2. Include the NiceTabLayout widget in your layout. This should usually be placed 19 | above the `ViewPager` it represents. 20 | 21 | 35 | 36 | 3. In your `onCreate` method (or `onCreateView` for a fragment), bind the 37 | widget to the `ViewPager`. 38 | 39 | // Initialize the ViewPager and set an adapter 40 | mViewPager = (ViewPager) view.findViewById(R.id.viewpager); 41 | mViewPager.setAdapter(new SampleFragmentPagerAdapter(getChildFragmentManager())); 42 | 43 | // Bind the tabs to the ViewPager 44 | mNiceTabLayout = (NiceTabLayout) view.findViewById(R.id.sliding_tabs); 45 | mNiceTabLayout.setViewPager(mViewPager); 46 | 47 | 4. *(Optional)* If you use an `OnPageChangeListener` with your view pager 48 | you should set it in the widget rather than on the pager directly. 49 | 50 | // continued from above 51 | mNiceTabLayout.setOnPageChangeListener(mPageChangeListener); 52 | 53 | 5. *(Optional)* If your adapter implements the interface `NiceTabLayout.IconTabProvider` you can add icon to tab view/s. 54 | The tab view should be a `Textview` or `ImageView` the icon will be used for textView's drawable top or 55 | imageView's image. 56 | 57 | # Customization 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | *Almost all attributes have their respective setters to change them at runtime* , open an issue if you miss any. 182 | 183 | # Developed By 184 | 185 | * Amiee Robot - 186 | * Check contributors list. 187 | 188 | # Credits 189 | 190 | * [ogaclejapan SmartTabLayout](https://github.com/ogaclejapan/SmartTabLayout) - A custom ViewPager title strip which gives continuous feedback to the user when scrolling 191 | * [googlesamples SlidingTabsColors](https://github.com/googlesamples/android-SlidingTabsColors) - Android SlidingTabsColors Sample 192 | * [500px 500px-android-blur](https://github.com/500px/500px-android-blur) - Android Blurring View 193 | 194 | # License 195 | 196 | Copyright 2015 Amiee Robot 197 | 198 | Licensed under the Apache License, Version 2.0 (the "License"); 199 | you may not use this file except in compliance with the License. 200 | You may obtain a copy of the License at 201 | 202 | http://www.apache.org/licenses/LICENSE-2.0 203 | 204 | Unless required by applicable law or agreed to in writing, software 205 | distributed under the License is distributed on an "AS IS" BASIS, 206 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 207 | See the License for the specific language governing permissions and 208 | limitations under the License. 209 | -------------------------------------------------------------------------------- /art/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/art/demo.gif -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.2.3' 9 | // NOTE: Do not place your application dependencies here; they belong 10 | // in the individual module build.gradle files 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | jcenter() 17 | } 18 | } -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /demo/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "me.amiee.nicetab.demo" 9 | minSdkVersion 9 10 | targetSdkVersion 23 11 | versionCode 2 12 | versionName "1.0.1" 13 | renderscriptSupportModeEnabled true 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile project(':library') 25 | compile 'com.android.support:appcompat-v7:23.0.1' 26 | compile 'com.android.support:recyclerview-v7:23.0.1' 27 | compile 'com.facebook.fresco:fresco:0.7.0' 28 | } 29 | -------------------------------------------------------------------------------- /demo/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/amiee/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /demo/src/androidTest/java/me/amiee/nicetab/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /demo/src/main/java/me/amiee/nicetab/demo/App.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab.demo; 2 | 3 | 4 | public class App { 5 | private String mName; 6 | private String mIconUrl; 7 | private String mAppUrl; 8 | 9 | public App(String name, String iconUrl, String appUrl) { 10 | mName = name; 11 | mIconUrl = iconUrl; 12 | mAppUrl = appUrl; 13 | } 14 | 15 | public String getName() { 16 | return mName; 17 | } 18 | 19 | public String getIconUrl() { 20 | return mIconUrl; 21 | } 22 | 23 | public String getAppUrl() { 24 | return mAppUrl; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/main/java/me/amiee/nicetab/demo/AppsAdapter.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab.demo; 2 | 3 | import android.net.Uri; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.facebook.drawee.view.SimpleDraweeView; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | 16 | public class AppsAdapter extends RecyclerView.Adapter { 17 | private OnItemClickedListener mOnItemClickedListener; 18 | 19 | public interface OnItemClickedListener { 20 | void onItemClicked(AppsAdapter appsAdapter, int position); 21 | } 22 | 23 | public static class AppViewHolder extends RecyclerView.ViewHolder { 24 | public SimpleDraweeView iconIv; 25 | public TextView nameTv; 26 | 27 | public AppViewHolder(View itemView) { 28 | super(itemView); 29 | iconIv = (SimpleDraweeView) itemView.findViewById(R.id.list_item_app_icon_iv); 30 | nameTv = (TextView) itemView.findViewById(R.id.list_item_app_name_tv); 31 | } 32 | } 33 | 34 | public AppsAdapter(OnItemClickedListener onItemClickedListener) { 35 | mOnItemClickedListener = onItemClickedListener; 36 | mApps = new ArrayList<>(); 37 | mApps.add(new App("StarMaker", 38 | "http://iosicongallery.com/iosicongallery/img/256/starmaker-2015.png", 39 | "https://itunes.apple.com/us/app/starmaker-sing-+-video-+-auto/id342138881")); 40 | mApps.add(new App("Let's Go Rocket - Ultimate Endless Space Adventure", 41 | "http://iosicongallery.com/iosicongallery/img/512/lets-go-rocket-2015.png", 42 | "https://itunes.apple.com/us/app/lets-go-rocket-ultimate-endless/id974628899")); 43 | mApps.add(new App("Vinyl Music and Video Files Manager", 44 | "http://iosicongallery.com/iosicongallery/img/256/vinyl-music-video-files-manager-2015.png", 45 | "https://itunes.apple.com/us/app/vinyl-music-video-files-manager/id938821819")); 46 | mApps.add(new App("Meh.", 47 | "http://iosicongallery.com/iosicongallery/img/256/meh.-2015.png", 48 | "https://itunes.apple.com/us/app/meh./id987393491")); 49 | mApps.add(new App("Enlight", 50 | "http://iosicongallery.com/iosicongallery/img/256/enlight-2015.png", 51 | "https://itunes.apple.com/us/app/enlight/id930026670")); 52 | mApps.add(new App("Sellf", 53 | "http://iosicongallery.com/iosicongallery/img/256/sellf-2015.png", 54 | "https://itunes.apple.com/us/app/sellf-your-personal-crm/id685969957")); 55 | mApps.add(new App("Alto's Adventure", 56 | "http://iosicongallery.com/iosicongallery/img/256/altos-adventure-2015.png", 57 | "https://itunes.apple.com/us/app/altos-adventure/id950812012")); 58 | mApps.add(new App("Monument Valley", 59 | "http://iosicongallery.com/iosicongallery/img/256/monument-valley-2015.png", 60 | "https://itunes.apple.com/us/app/monument-valley/id728293409")); 61 | mApps.add(new App("Tubex for YouTube", 62 | "http://iosicongallery.com/iosicongallery/img/256/tubex-for-youtube-2014.png", 63 | "https://itunes.apple.com/us/app/tubex-for-youtube/id939906112")); 64 | mApps.add(new App("AirPano Travel Book", 65 | "http://iosicongallery.com/iosicongallery/img/256/airpano-travel-book-2014.png", 66 | "https://itunes.apple.com/us/app/airpano-travel-book/id887138564")); 67 | mApps.add(new App("StarMaker", 68 | "http://iosicongallery.com/iosicongallery/img/256/starmaker-2015.png", 69 | "https://itunes.apple.com/us/app/starmaker-sing-+-video-+-auto/id342138881")); 70 | mApps.add(new App("Let's Go Rocket - Ultimate Endless Space Adventure", 71 | "http://iosicongallery.com/iosicongallery/img/512/lets-go-rocket-2015.png", 72 | "https://itunes.apple.com/us/app/lets-go-rocket-ultimate-endless/id974628899")); 73 | mApps.add(new App("Vinyl Music and Video Files Manager", 74 | "http://iosicongallery.com/iosicongallery/img/256/vinyl-music-video-files-manager-2015.png", 75 | "https://itunes.apple.com/us/app/vinyl-music-video-files-manager/id938821819")); 76 | mApps.add(new App("Meh.", 77 | "http://iosicongallery.com/iosicongallery/img/256/meh.-2015.png", 78 | "https://itunes.apple.com/us/app/meh./id987393491")); 79 | mApps.add(new App("Enlight", 80 | "http://iosicongallery.com/iosicongallery/img/256/enlight-2015.png", 81 | "https://itunes.apple.com/us/app/enlight/id930026670")); 82 | mApps.add(new App("Sellf", 83 | "http://iosicongallery.com/iosicongallery/img/256/sellf-2015.png", 84 | "https://itunes.apple.com/us/app/sellf-your-personal-crm/id685969957")); 85 | mApps.add(new App("Alto's Adventure", 86 | "http://iosicongallery.com/iosicongallery/img/256/altos-adventure-2015.png", 87 | "https://itunes.apple.com/us/app/altos-adventure/id950812012")); 88 | mApps.add(new App("Monument Valley", 89 | "http://iosicongallery.com/iosicongallery/img/256/monument-valley-2015.png", 90 | "https://itunes.apple.com/us/app/monument-valley/id728293409")); 91 | mApps.add(new App("Tubex for YouTube", 92 | "http://iosicongallery.com/iosicongallery/img/256/tubex-for-youtube-2014.png", 93 | "https://itunes.apple.com/us/app/tubex-for-youtube/id939906112")); 94 | mApps.add(new App("AirPano Travel Book", 95 | "http://iosicongallery.com/iosicongallery/img/256/airpano-travel-book-2014.png", 96 | "https://itunes.apple.com/us/app/airpano-travel-book/id887138564")); 97 | } 98 | 99 | private List mApps; 100 | 101 | public App getItem(int position) { 102 | return mApps.get(position); 103 | } 104 | 105 | @Override 106 | public int getItemCount() { 107 | return mApps.size(); 108 | } 109 | 110 | @Override 111 | public long getItemId(int position) { 112 | return position; 113 | } 114 | 115 | @Override 116 | public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 117 | AppViewHolder itemViewHolder = (AppViewHolder) holder; 118 | Uri uri = Uri.parse(mApps.get(position).getIconUrl()); 119 | itemViewHolder.iconIv.setImageURI(uri); 120 | itemViewHolder.nameTv.setText(mApps.get(position).getName()); 121 | itemViewHolder.itemView.setOnClickListener(new View.OnClickListener() { 122 | @Override 123 | public void onClick(View v) { 124 | if (mOnItemClickedListener != null) { 125 | mOnItemClickedListener.onItemClicked(AppsAdapter.this, position); 126 | } 127 | } 128 | }); 129 | } 130 | 131 | @Override 132 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 133 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false); 134 | return new AppViewHolder(v); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /demo/src/main/java/me/amiee/nicetab/demo/AppsFragment.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab.demo; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v7.widget.DefaultItemAnimator; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | 15 | public class AppsFragment extends Fragment implements AppsAdapter.OnItemClickedListener { 16 | private RecyclerView mRecyclerView; 17 | 18 | public static AppsFragment newInstance() { 19 | AppsFragment fragment = new AppsFragment(); 20 | return fragment; 21 | } 22 | 23 | public AppsFragment() { 24 | } 25 | 26 | @Override 27 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 28 | Bundle savedInstanceState) { 29 | mRecyclerView = (RecyclerView) inflater.inflate(R.layout.fragment_apps, container, false); 30 | return mRecyclerView; 31 | } 32 | 33 | @Override 34 | public void onViewCreated(View view, Bundle savedInstanceState) { 35 | super.onViewCreated(view, savedInstanceState); 36 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); 37 | linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); 38 | mRecyclerView.setLayoutManager(linearLayoutManager); 39 | 40 | mRecyclerView.setItemAnimator(new DefaultItemAnimator()); 41 | mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.color.divider_color, R.dimen.divider_height, DividerItemDecoration.VERTICAL_LIST)); 42 | 43 | final DemoFragment demoFragment = (DemoFragment) getParentFragment(); 44 | 45 | AppsAdapter appsAdapter = new AppsAdapter(this); 46 | mRecyclerView.setAdapter(appsAdapter); 47 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 48 | @Override 49 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 50 | super.onScrolled(recyclerView, dx, dy); 51 | demoFragment.invalidateBlur(); 52 | } 53 | }); 54 | } 55 | 56 | @Override 57 | public void onItemClicked(AppsAdapter appsAdapter, int position) { 58 | Uri uri = Uri.parse(appsAdapter.getItem(position).getAppUrl()); 59 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 60 | startActivity(intent); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /demo/src/main/java/me/amiee/nicetab/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab.demo; 2 | 3 | 4 | import android.app.Application; 5 | 6 | import com.facebook.drawee.backends.pipeline.Fresco; 7 | 8 | public class DemoApplication extends Application { 9 | 10 | @Override 11 | public void onCreate() { 12 | super.onCreate(); 13 | Fresco.initialize(this); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /demo/src/main/java/me/amiee/nicetab/demo/DemoFragment.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab.demo; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentManager; 7 | import android.support.v4.app.FragmentPagerAdapter; 8 | import android.support.v4.view.ViewPager; 9 | import android.support.v7.widget.Toolbar; 10 | import android.util.Log; 11 | import android.view.LayoutInflater; 12 | import android.view.Menu; 13 | import android.view.MenuInflater; 14 | import android.view.MenuItem; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.FrameLayout; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import me.amiee.nicetab.NiceTabLayout; 23 | import me.amiee.nicetab.NiceTabStrip; 24 | 25 | 26 | public class DemoFragment extends Fragment { 27 | private boolean mIosStyleIcon = false; 28 | 29 | public static DemoFragment newInstance( ) { 30 | DemoFragment fragment = new DemoFragment(); 31 | Bundle args = new Bundle(); 32 | fragment.setArguments(args); 33 | return fragment; 34 | } 35 | 36 | public DemoFragment() { 37 | } 38 | 39 | @Override 40 | public void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | if (getArguments() != null) { 43 | } 44 | 45 | mTabs.add(new SamplePagerItem( 46 | getString(R.string.tab_home), // Title 47 | R.drawable.ic_home, // Icon 48 | R.drawable.ic_home_a, // Icon 49 | getResources().getColor(R.color.home), // Indicator color 50 | getResources().getColor(R.color.home) // Divider color 51 | )); 52 | 53 | mTabs.add(new SamplePagerItem( 54 | getString(R.string.tab_activity), // Title 55 | R.drawable.ic_activity, // Icon 56 | R.drawable.ic_activity_a, // Icon 57 | getResources().getColor(R.color.activity), // Indicator color 58 | getResources().getColor(R.color.activity) // Divider color 59 | )); 60 | 61 | mTabs.add(new SamplePagerItem( 62 | getString(R.string.tab_search), // Title 63 | R.drawable.ic_search, // Icon 64 | R.drawable.ic_search_a, // Icon 65 | getResources().getColor(R.color.search), // Indicator color 66 | getResources().getColor(R.color.search) // Divider color 67 | )); 68 | 69 | mTabs.add(new SamplePagerItem( 70 | getString(R.string.tab_me), // Title 71 | R.drawable.ic_me, // Icon 72 | R.drawable.ic_me_a, // Icon 73 | getResources().getColor(R.color.me), // Indicator color 74 | getResources().getColor(R.color.me) // Divider color 75 | )); 76 | 77 | mTabs.add(new SamplePagerItem( 78 | getString(R.string.tab_long_long_title), // Title 79 | R.drawable.ic_coffee, // Icon 80 | R.drawable.ic_coffee_a, // Icon 81 | getResources().getColor(R.color.coffee), // Indicator color 82 | getResources().getColor(R.color.coffee) // Divider color 83 | )); 84 | } 85 | 86 | static class SamplePagerItem { 87 | private final CharSequence mTitle; 88 | private final int mIosIconResId; 89 | private final int mAndroidIconResId; 90 | private final int mIndicatorColor; 91 | private final int mDividerColor; 92 | 93 | SamplePagerItem(CharSequence title, int iosIconResId, int androidIconResId, int indicatorColor, int dividerColor) { 94 | mTitle = title; 95 | mIosIconResId = iosIconResId; 96 | mAndroidIconResId = androidIconResId; 97 | mIndicatorColor = indicatorColor; 98 | mDividerColor = dividerColor; 99 | } 100 | 101 | Fragment createFragment() { 102 | return AppsFragment.newInstance(); 103 | } 104 | 105 | CharSequence getTitle() { 106 | return mTitle; 107 | } 108 | 109 | int getIosIconResId() { 110 | return mIosIconResId; 111 | } 112 | 113 | int getAndroidIconResId() { 114 | return mAndroidIconResId; 115 | } 116 | 117 | int getIndicatorColor() { 118 | return mIndicatorColor; 119 | } 120 | 121 | int getDividerColor() { 122 | return mDividerColor; 123 | } 124 | } 125 | 126 | private NiceTabLayout mNiceTabLayout; 127 | private FrameLayout mWrapFl; 128 | private ViewPager mViewPager; 129 | private Toolbar mToolbar; 130 | 131 | private List mTabs = new ArrayList<>(); 132 | 133 | @Override 134 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 135 | Bundle savedInstanceState) { 136 | return inflater.inflate(R.layout.fragment_demo, container, false); 137 | } 138 | 139 | @Override 140 | public void onViewCreated(View view, Bundle savedInstanceState) { 141 | setHasOptionsMenu(true); 142 | 143 | mWrapFl = (FrameLayout) view.findViewById(R.id.wrap_fl); 144 | 145 | mViewPager = (ViewPager) view.findViewById(R.id.viewpager); 146 | mViewPager.setAdapter(new SampleFragmentPagerAdapter(getChildFragmentManager())); 147 | 148 | mNiceTabLayout = (NiceTabLayout) view.findViewById(R.id.sliding_tabs); 149 | mNiceTabLayout.setViewPager(mViewPager); 150 | 151 | mNiceTabLayout.setTabStripColorize(new NiceTabStrip.TabStripColorize() { 152 | 153 | @Override 154 | public int getIndicatorColor(int position) { 155 | return mTabs.get(position).getIndicatorColor(); 156 | } 157 | 158 | @Override 159 | public int getDividerColor(int position) { 160 | return mTabs.get(position).getDividerColor(); 161 | } 162 | }); 163 | 164 | mNiceTabLayout.setTabColorize(new NiceTabLayout.TabColorize() { 165 | 166 | @Override 167 | public int getDefaultTabColor(int position) { 168 | if (isAdded()) { 169 | return getResources().getColor(android.R.color.white); 170 | } else { 171 | return Color.WHITE; 172 | } 173 | } 174 | 175 | @Override 176 | public int getSelectedTabColor(int position) { 177 | return mTabs.get(position).getIndicatorColor(); 178 | } 179 | }); 180 | 181 | mNiceTabLayout.setOnIndicatorColorChangedListener((MainActivity) getActivity()); 182 | 183 | mToolbar = (Toolbar) view.findViewById(R.id.demo_toolbar); 184 | mToolbar.inflateMenu(R.menu.demo_bottom); 185 | mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { 186 | @Override 187 | public boolean onMenuItemClick(MenuItem item) { 188 | switch (item.getItemId()) { 189 | case R.id.indicator_underline_divider: { 190 | mNiceTabLayout.setDrawOrder(NiceTabStrip.DrawOrder.INDICATOR_UNDERLINE_DIVIDER); 191 | return true; 192 | } 193 | case R.id.indicator_divider_underline: { 194 | mNiceTabLayout.setDrawOrder(NiceTabStrip.DrawOrder.INDICATOR_DIVIDER_UNDERLINE); 195 | return true; 196 | } 197 | case R.id.underline_indicator_divider: { 198 | mNiceTabLayout.setDrawOrder(NiceTabStrip.DrawOrder.UNDERLINE_INDICATOR_DIVIDER); 199 | return true; 200 | } 201 | case R.id.underline_divider_indicator: { 202 | mNiceTabLayout.setDrawOrder(NiceTabStrip.DrawOrder.UNDERLINE_DIVIDER_INDICATOR); 203 | return true; 204 | } 205 | case R.id.divider_indicator_underline: { 206 | mNiceTabLayout.setDrawOrder(NiceTabStrip.DrawOrder.DIVIDER_INDICATOR_UNDERLINE); 207 | return true; 208 | } 209 | case R.id.divider_underline_indicator: { 210 | mNiceTabLayout.setDrawOrder(NiceTabStrip.DrawOrder.DIVIDER_UNDERLINE_INDICATOR); 211 | return true; 212 | } 213 | ////////// 214 | case R.id.show_underline: { 215 | mNiceTabLayout.setShowUnderline(true); 216 | return true; 217 | } 218 | case R.id.hide_underline: { 219 | mNiceTabLayout.setShowUnderline(false); 220 | return true; 221 | } 222 | case R.id.show_divider: { 223 | mNiceTabLayout.setShowDivider(true); 224 | return true; 225 | } 226 | case R.id.hide_divider: { 227 | mNiceTabLayout.setShowDivider(false); 228 | return true; 229 | } 230 | case R.id.show_indicator: { 231 | mNiceTabLayout.setShowIndicator(true); 232 | return true; 233 | } 234 | case R.id.hide_indicator: { 235 | mNiceTabLayout.setShowIndicator(false); 236 | return true; 237 | } 238 | ////////// 239 | case R.id.fit_content_width: { 240 | mNiceTabLayout.setDistributeEvenly(false); 241 | return true; 242 | } 243 | case R.id.distribute_evenly: { 244 | mNiceTabLayout.setDistributeEvenly(true); 245 | return true; 246 | } 247 | ////////// 248 | case R.id.left: { 249 | mNiceTabLayout.setTabSelectedCenter(false); 250 | return true; 251 | } 252 | case R.id.center: { 253 | mNiceTabLayout.setTabSelectedCenter(true); 254 | return true; 255 | } 256 | ////////// 257 | case R.id.test_badge: { 258 | testBadge(); 259 | return true; 260 | } 261 | case R.id.clear_badge: { 262 | clearBadge(); 263 | return true; 264 | } 265 | ////////// 266 | case R.id.ios: { 267 | mNiceTabLayout.setBlurredView(mWrapFl, Color.WHITE); // white is window's background color 268 | mIosStyleIcon = true; 269 | mNiceTabLayout.setViewPager(mViewPager); 270 | return true; 271 | } 272 | case R.id.android: { 273 | mNiceTabLayout.setBlurredView(null, 0); 274 | mIosStyleIcon = false; 275 | mNiceTabLayout.setViewPager(mViewPager); 276 | return true; 277 | } 278 | } 279 | return false; 280 | } 281 | }); 282 | } 283 | 284 | private void testBadge() { 285 | mNiceTabLayout.setBadge(0, "1"); 286 | mNiceTabLayout.setBadge(1, "12"); 287 | mNiceTabLayout.setBadge(2, "123"); 288 | mNiceTabLayout.setBadge(3, "1234567"); 289 | mNiceTabLayout.setBadgeSmall(4); 290 | 291 | Log.d("DemoFragment", mNiceTabLayout.getBadgeText(3)); 292 | } 293 | 294 | private void clearBadge() { 295 | mNiceTabLayout.clearBadge(); 296 | } 297 | 298 | @Override 299 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 300 | inflater.inflate(R.menu.demo, menu); 301 | } 302 | 303 | @Override 304 | public boolean onOptionsItemSelected(MenuItem item) { 305 | switch (item.getItemId()) { 306 | case R.id.action_title_only: { 307 | mNiceTabLayout.setTabMode(NiceTabLayout.TabMode.TITLE_ONLY); 308 | return true; 309 | } 310 | case R.id.action_icon_only: { 311 | mNiceTabLayout.setTabMode(NiceTabLayout.TabMode.ICON_ONLY); 312 | return true; 313 | } 314 | case R.id.action_both: { 315 | mNiceTabLayout.setTabMode(NiceTabLayout.TabMode.BOTH); 316 | return true; 317 | } 318 | case R.id.action_none: { 319 | mNiceTabLayout.setTabColorBlendMode(NiceTabLayout.TabColorBlendMode.NONE); 320 | return true; 321 | } 322 | case R.id.action_default_selected: { 323 | mNiceTabLayout.setTabColorBlendMode(NiceTabLayout.TabColorBlendMode.DEFAULT_SELECTED); 324 | return true; 325 | } 326 | case R.id.action_next_selected: { 327 | mNiceTabLayout.setTabColorBlendMode(NiceTabLayout.TabColorBlendMode.NEXT_SELECTED); 328 | return true; 329 | } 330 | } 331 | return super.onOptionsItemSelected(item); 332 | } 333 | 334 | @Override 335 | public void onDetach() { 336 | super.onDetach(); 337 | mNiceTabLayout.setOnIndicatorColorChangedListener(null); 338 | } 339 | 340 | class SampleFragmentPagerAdapter extends FragmentPagerAdapter implements NiceTabLayout.IconTabProvider { 341 | 342 | SampleFragmentPagerAdapter(FragmentManager fm) { 343 | super(fm); 344 | } 345 | 346 | @Override 347 | public Fragment getItem(int i) { 348 | return mTabs.get(i).createFragment(); 349 | } 350 | 351 | @Override 352 | public int getCount() { 353 | return mTabs.size(); 354 | } 355 | 356 | @Override 357 | public CharSequence getPageTitle(int position) { 358 | return mTabs.get(position).getTitle(); 359 | } 360 | 361 | @Override 362 | public int getPageIconResId(int position) { 363 | return mIosStyleIcon ? mTabs.get(position).getIosIconResId() : mTabs.get(position).getAndroidIconResId(); 364 | } 365 | } 366 | 367 | public void invalidateBlur() { 368 | mNiceTabLayout.invalidateBlur(); 369 | } 370 | } -------------------------------------------------------------------------------- /demo/src/main/java/me/amiee/nicetab/demo/DividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab.demo; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | 10 | /** 11 | * Created by amiee on 15/5/20. 12 | * Last Modified by amiee on 15/5/20. 13 | */ 14 | public class DividerItemDecoration extends RecyclerView.ItemDecoration { 15 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; 16 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; 17 | private Paint mPaint; 18 | private int mOrientation; 19 | 20 | public DividerItemDecoration(Context context, int colorResId, int heightResId, int orientation) { 21 | mPaint = new Paint(); 22 | mPaint.setColor(context.getResources().getColor(colorResId)); 23 | mPaint.setStrokeWidth(context.getResources().getDimensionPixelSize(heightResId)); 24 | setOrientation(orientation); 25 | } 26 | 27 | public void setOrientation(int orientation) { 28 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { 29 | throw new IllegalArgumentException("invalid orientation"); 30 | } 31 | mOrientation = orientation; 32 | } 33 | 34 | @Override 35 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 36 | if (mOrientation == VERTICAL_LIST) { 37 | drawVertical(c, parent); 38 | } else { 39 | drawHorizontal(c, parent); 40 | } 41 | } 42 | 43 | public void drawVertical(Canvas c, RecyclerView parent) { 44 | final int left = parent.getPaddingLeft(); 45 | final int right = parent.getWidth() - parent.getPaddingRight(); 46 | final int childCount = parent.getChildCount(); 47 | for (int i = 0; i < childCount; i++) { 48 | final View child = parent.getChildAt(i); 49 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 50 | .getLayoutParams(); 51 | final int top = child.getBottom() + params.bottomMargin; 52 | final int bottom = top + (int) mPaint.getStrokeWidth(); 53 | c.drawRect(left, top, right, bottom, mPaint); 54 | } 55 | } 56 | 57 | public void drawHorizontal(Canvas c, RecyclerView parent) { 58 | final int top = parent.getPaddingTop(); 59 | final int bottom = parent.getHeight() - parent.getPaddingBottom(); 60 | final int childCount = parent.getChildCount(); 61 | for (int i = 0; i < childCount; i++) { 62 | final View child = parent.getChildAt(i); 63 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child 64 | .getLayoutParams(); 65 | final int left = child.getRight() + params.rightMargin; 66 | final int right = left + (int) mPaint.getStrokeWidth(); 67 | c.drawRect(left, top, right, bottom, mPaint); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /demo/src/main/java/me/amiee/nicetab/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab.demo; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v4.app.FragmentTransaction; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.Menu; 10 | import android.view.MenuItem; 11 | 12 | import me.amiee.nicetab.NiceTabLayout; 13 | import me.amiee.nicetab.NiceTabStrip; 14 | 15 | public class MainActivity extends AppCompatActivity implements NiceTabStrip.OnIndicatorColorChangedListener { 16 | private Toolbar mToolbar; 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_main); 22 | 23 | mToolbar = (Toolbar) findViewById(R.id.main_toolbar); 24 | setSupportActionBar(mToolbar); 25 | 26 | mToolbar.showOverflowMenu(); 27 | 28 | if (savedInstanceState == null) { 29 | FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 30 | transaction.replace(R.id.main_fl, DemoFragment.newInstance()); 31 | transaction.commit(); 32 | } 33 | } 34 | 35 | @Override 36 | public boolean onCreateOptionsMenu(Menu menu) { 37 | getMenuInflater().inflate(R.menu.main, menu); 38 | return true; 39 | } 40 | 41 | @Override 42 | public boolean onOptionsItemSelected(MenuItem item) { 43 | switch (item.getItemId()) { 44 | case R.id.action_github: 45 | Uri uri = Uri.parse(getString(R.string.github_url)); 46 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 47 | startActivity(intent); 48 | return true; 49 | } 50 | 51 | return super.onOptionsItemSelected(item); 52 | } 53 | 54 | @Override 55 | public void onIndicatorColorChanged(NiceTabLayout tabLayout, int color) { 56 | // tabLayout.setBackgroundColor(color); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_activity_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_activity_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_activity_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_activity_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_activity_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_activity_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_arrow_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_arrow_back.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_coffee_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_coffee_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_coffee_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_coffee_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_coffee_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_coffee_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_github.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_home_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_home_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_home_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_home_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_home_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_home_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_me_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_me_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_me_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_me_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_me_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_me_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_search_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_search_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_search_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_search_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-hdpi/ic_search_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-hdpi/ic_search_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_activity_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_activity_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_activity_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_activity_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_activity_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_activity_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_arrow_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_arrow_back.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_coffee_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_coffee_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_coffee_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_coffee_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_coffee_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_coffee_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_github.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_home_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_home_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_home_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_home_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_home_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_home_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_me_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_me_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_me_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_me_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_me_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_me_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_search_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_search_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_search_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_search_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-mdpi/ic_search_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-mdpi/ic_search_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_activity_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_activity_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_activity_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_activity_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_activity_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_activity_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_arrow_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_arrow_back.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_coffee_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_coffee_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_coffee_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_coffee_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_coffee_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_coffee_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_github.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_home_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_home_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_home_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_home_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_home_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_home_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_me_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_me_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_me_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_me_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_me_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_me_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_search_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_search_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_search_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_search_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xhdpi/ic_search_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xhdpi/ic_search_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/bg_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/bg_badge.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_activity_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_activity_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_activity_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_activity_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_activity_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_activity_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_arrow_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_arrow_back.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_coffee_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_coffee_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_coffee_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_coffee_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_coffee_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_coffee_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_github.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_home_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_home_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_home_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_home_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_home_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_home_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_me_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_me_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_me_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_me_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_me_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_me_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_search_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_search_a.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_search_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_search_default.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable-xxhdpi/ic_search_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/drawable-xxhdpi/ic_search_selected.png -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_coffee.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_me.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 16 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/custom_tab.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/fragment_apps.xml: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/fragment_demo.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | 21 | 22 | 26 | 27 | 28 | 29 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/fragment_demos.xml: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/layout_basic.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/list_item_app.xml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 22 | 23 | 30 | 31 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/list_item_demo.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/main/res/menu/demo.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | 32 | 33 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /demo/src/main/res/menu/demo_bottom.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | 14 | 15 | 17 | 18 | 20 | 21 | 23 | 24 | 26 | 27 | 29 | 30 | 31 | 32 | 37 | 38 | 39 | 41 | 42 | 44 | 45 | 47 | 48 | 50 | 51 | 53 | 54 | 56 | 57 | 58 | 59 | 64 | 65 | 66 | 68 | 69 | 71 | 72 | 73 | 74 | 79 | 80 | 81 | 83 | 84 | 86 | 87 | 88 | 89 | 94 | 95 | 96 | 98 | 99 | 101 | 102 | 103 | 104 | 109 | 110 | 111 | 113 | 114 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /demo/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/values-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 40dp 3 | @dimen/abc_text_size_caption_material 4 | 10sp 5 | 2dp 6 | 7 | -------------------------------------------------------------------------------- /demo/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 基本用法 3 | 首页 4 | 动态 5 | 搜索 6 | 7 | 长长的标题 8 | 显示模式 9 | 显示标题和图标 10 | 只显示图标 11 | 只显示标题 12 | 颜色过度模式 13 | 14 | 默认选中 15 | 相邻选中 16 | 绘制顺序 17 | 指示条 底线 分割线 18 | 指示条 分割线 底线 19 | 底线 指示条 分割线 20 | 底线 分割线 指示条 21 | 分割线 指示条 底线 22 | 分割线 底线 指示条 23 | 显示隐藏 24 | 显示底线 25 | 隐藏底线 26 | 显示分割线 27 | 隐藏分割线 28 | 显示指示条 29 | 隐藏指示条 30 | Tab 布局 31 | 自适应宽度 32 | 等宽显示 33 | Tab选中位置 34 | 左边 35 | 居中 36 | Tab 小圆点 37 | 测试小圆点 38 | 清空小圆点 39 | Tab 图标风格 40 | 41 | -------------------------------------------------------------------------------- /demo/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #3F51B5 3 | #303F9F 4 | #22000000 5 | #333 6 | #99000000 7 | 8 | #4CAF50 9 | #E91E63 10 | #2196F3 11 | #9C27B0 12 | #795548 13 | -------------------------------------------------------------------------------- /demo/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 48dp 3 | 8dp 4 | 1px 5 | @dimen/abc_text_size_subhead_material 6 | @dimen/abc_text_size_caption_material 7 | 4dp 8 | 9 | -------------------------------------------------------------------------------- /demo/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /demo/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | NiceTab 3 | GitHub 4 | 5 | Basic 6 | Home 7 | Activity 8 | Search 9 | Me 10 | Long Long Title 11 | Show Mode 12 | Show Title Only 13 | Show Icon Only 14 | Show title and icon 15 | Tab Color Blend Mode 16 | None 17 | Default Selected 18 | Next Selected 19 | Draw Order 20 | Indicator Underline Divider 21 | Indicator Divider Underline 22 | Underline Indicator Divider 23 | Underline Divider Indicator 24 | Divider Indicator Underline 25 | Divider Underline Indicator 26 | Show Hide 27 | Show Underline 28 | Hide Underline 29 | Show Divider 30 | Hide Divider 31 | Show Indicator 32 | Hide Indicator 33 | Tab Layout 34 | Tab Fit Content Width 35 | Distribute Evenly 36 | Tab Selected Position 37 | Left 38 | Center 39 | Tab Badge 40 | Test Badge 41 | Clear Badge 42 | Tab Icon Style 43 | iOS 44 | Android 45 | 46 | -------------------------------------------------------------------------------- /demo/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | VERSION_NAME=1.0.0 2 | VERSION_CODE=1 3 | POM_GROUP_ID=me.amiee 4 | POM_DESCRIPTION=A nice tab to navigate between the different pages of a ViewPager. 5 | POM_URL=https://github.com/RobotAmiee/Android-NiceTab 6 | POM_SCM_URL=https://github.com/RobotAmiee/Android-NiceTab.git 7 | POM_SCM_CONNECTION=scm:git@github.com:RobotAmiee/Android-NiceTab.git 8 | POM_SCM_DEV_CONNECTION=scm:git@github.com:RobotAmiee/Android-NiceTab.git 9 | POM_LICENCE_NAME=Apache License 2.0 10 | POM_LICENCE_URL=https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/master/LICENSE 11 | POM_LICENCE_DIST=repo 12 | POM_DEVELOPER_ID=amiee 13 | POM_DEVELOPER_NAME=Amiee Robot 14 | POM_INCEPTION_YEAR=2015 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotAmiee/Android-NiceTab/96fb02f04ea7c145526bc14d4532a80a88f5eb1f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed May 13 09:56:34 GMT+08:00 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 4 9 | targetSdkVersion 23 10 | versionCode 2 11 | versionName "1.0.1" 12 | renderscriptSupportModeEnabled true 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile "com.android.support:support-v4:23.0.1" 24 | } 25 | 26 | apply from: '../maven_push.gradle' -------------------------------------------------------------------------------- /library/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Android-NiceTab 2 | POM_ARTIFACT_ID=nicetab 3 | POM_PACKAGING=aar -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/amiee/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /library/src/androidTest/java/me/amiee/nicetab/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /library/src/main/java/me/amiee/nicetab/Badge.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab; 2 | 3 | 4 | class Badge { 5 | private boolean mSmall; 6 | private String mText; 7 | 8 | Badge(String text) { 9 | mText = text; 10 | mSmall = false; 11 | } 12 | 13 | Badge() { 14 | mSmall = true; 15 | } 16 | 17 | boolean isSmall() { 18 | return mSmall; 19 | } 20 | 21 | void setSmall(boolean small) { 22 | mSmall = small; 23 | } 24 | 25 | String getText() { 26 | return mText; 27 | } 28 | 29 | void setText(String text) { 30 | mText = text; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /library/src/main/java/me/amiee/nicetab/ColorUtils.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab; 2 | 3 | import android.graphics.Color; 4 | 5 | 6 | class ColorUtils { 7 | /** 8 | * Blend {@code color1} and {@code color2} using the given ratio. 9 | * 10 | * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, 11 | * 0.0 will return {@code color2}. 12 | */ 13 | public static int blendColors(int color1, int color2, float ratio) { 14 | final float inverseRation = 1f - ratio; 15 | float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); 16 | float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); 17 | float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); 18 | return Color.rgb((int) r, (int) g, (int) b); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /library/src/main/java/me/amiee/nicetab/CrossFadeDrawable.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.ColorFilter; 5 | import android.graphics.PorterDuff; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.Drawable; 8 | 9 | 10 | class CrossFadeDrawable extends Drawable implements Drawable.Callback { 11 | private Drawable mFading; 12 | private Drawable mBase; 13 | private float mProgress; 14 | private int mAlpha; 15 | private int mChangingConfigs; 16 | private ColorFilter mColorFilter; 17 | private boolean mFilterBitmap; 18 | private boolean mDither; 19 | private int mColorFilterColor; 20 | private PorterDuff.Mode mColorFilterMode; 21 | 22 | public CrossFadeDrawable() { 23 | } 24 | 25 | public void setFading(Drawable d) { 26 | if (mFading != d) { 27 | if (mFading != null) { 28 | mFading.setCallback(null); 29 | } 30 | 31 | mFading = d; 32 | if (d != null) { 33 | initDrawable(d); 34 | } 35 | 36 | invalidateSelf(); 37 | } 38 | } 39 | 40 | public void setBase(Drawable d) { 41 | if (mBase != d) { 42 | if (mBase != null) { 43 | mBase.setCallback(null); 44 | } 45 | 46 | mBase = d; 47 | initDrawable(d); 48 | invalidateSelf(); 49 | } 50 | } 51 | 52 | public void setProgress(float progress) { 53 | float updated = clamp(progress); 54 | if (updated != mProgress) { 55 | mProgress = updated; 56 | invalidateSelf(); 57 | } 58 | } 59 | 60 | private float clamp(float value) { 61 | return value < 0f ? 0f : (value > 1f ? 1f : value); 62 | } 63 | 64 | private void initDrawable(Drawable d) { 65 | d.setCallback(this); 66 | d.setState(getState()); 67 | if (mColorFilter != null) { 68 | d.setColorFilter(mColorFilter); 69 | } 70 | 71 | if (mColorFilterMode != null) { 72 | d.setColorFilter(mColorFilterColor, mColorFilterMode); 73 | } 74 | 75 | d.setDither(mDither); 76 | d.setFilterBitmap(mFilterBitmap); 77 | d.setBounds(getBounds()); 78 | } 79 | 80 | @Override 81 | public void draw(Canvas canvas) { 82 | if (mBase != null && (mProgress < 1.0F || mFading == null)) { 83 | mBase.setAlpha(255); 84 | mBase.draw(canvas); 85 | } 86 | 87 | if (mFading != null && mProgress > 0.0F) { 88 | mFading.setAlpha((int) (255.0F * mProgress)); 89 | mFading.draw(canvas); 90 | } 91 | } 92 | 93 | @Override 94 | public int getIntrinsicWidth() { 95 | int fading = mFading == null ? -1 : mFading.getIntrinsicWidth(); 96 | int base = mBase == null ? -1 : mBase.getIntrinsicHeight(); 97 | return Math.max(fading, base); 98 | } 99 | 100 | @Override 101 | public int getIntrinsicHeight() { 102 | int fading = mFading == null ? -1 : mFading.getIntrinsicHeight(); 103 | int base = mBase == null ? -1 : mBase.getIntrinsicHeight(); 104 | return Math.max(fading, base); 105 | } 106 | 107 | @Override 108 | protected void onBoundsChange(Rect bounds) { 109 | if (mBase != null) { 110 | mBase.setBounds(bounds); 111 | } 112 | 113 | if (mFading != null) { 114 | mFading.setBounds(bounds); 115 | } 116 | 117 | invalidateSelf(); 118 | } 119 | 120 | // @Override 121 | // public void jumpToCurrentState() { 122 | // if (mFading != null) { 123 | // mFading.jumpToCurrentState(); 124 | // } 125 | // 126 | // if (mBase != null) { 127 | // mBase.jumpToCurrentState(); 128 | // } 129 | // } 130 | 131 | @Override 132 | public void setChangingConfigurations(int configs) { 133 | if (mChangingConfigs != configs) { 134 | mChangingConfigs = configs; 135 | if (mFading != null) { 136 | mFading.setChangingConfigurations(configs); 137 | } 138 | 139 | if (mBase != null) { 140 | mBase.setChangingConfigurations(configs); 141 | } 142 | } 143 | } 144 | 145 | @Override 146 | public void setFilterBitmap(boolean filter) { 147 | if (mFilterBitmap != filter) { 148 | mFilterBitmap = filter; 149 | if (mFading != null) { 150 | mFading.setFilterBitmap(filter); 151 | } 152 | 153 | if (mBase != null) { 154 | mBase.setFilterBitmap(filter); 155 | } 156 | } 157 | } 158 | 159 | @Override 160 | public void setDither(boolean dither) { 161 | if (mDither != dither) { 162 | mDither = dither; 163 | if (mFading != null) { 164 | mFading.setDither(dither); 165 | } 166 | 167 | if (mBase != null) { 168 | mBase.setDither(dither); 169 | } 170 | } 171 | } 172 | 173 | @Override 174 | public void setColorFilter(ColorFilter cf) { 175 | if (mColorFilter != cf) { 176 | mColorFilter = cf; 177 | if (mFading != null) { 178 | mFading.setColorFilter(cf); 179 | } 180 | 181 | if (mBase != null) { 182 | mBase.setColorFilter(cf); 183 | } 184 | } 185 | } 186 | 187 | @Override 188 | public void setColorFilter(int color, PorterDuff.Mode mode) { 189 | if (mColorFilterColor != color || mColorFilterMode != mode) { 190 | mColorFilterColor = color; 191 | mColorFilterMode = mode; 192 | if (mFading != null) { 193 | mFading.setColorFilter(color, mode); 194 | } 195 | 196 | if (mBase != null) { 197 | mBase.setColorFilter(color, mode); 198 | } 199 | } 200 | } 201 | 202 | @Override 203 | public void clearColorFilter() { 204 | if (mColorFilterMode != null) { 205 | mColorFilterMode = null; 206 | if (mFading != null) { 207 | mFading.clearColorFilter(); 208 | } 209 | 210 | if (mBase != null) { 211 | mBase.clearColorFilter(); 212 | } 213 | } 214 | } 215 | 216 | @Override 217 | public int getChangingConfigurations() { 218 | return mChangingConfigs; 219 | } 220 | 221 | @Override 222 | protected boolean onStateChange(int[] state) { 223 | boolean changed = false; 224 | if (mFading != null) { 225 | changed = mFading.setState(state); 226 | } 227 | 228 | if (mBase != null) { 229 | changed |= mBase.setState(state); 230 | } 231 | 232 | return changed; 233 | } 234 | 235 | @Override 236 | protected boolean onLevelChange(int level) { 237 | boolean changed = false; 238 | if (mFading != null) { 239 | changed = mFading.setLevel(level); 240 | } 241 | 242 | if (mBase != null) { 243 | changed |= mBase.setLevel(level); 244 | } 245 | 246 | return changed; 247 | } 248 | 249 | @Override 250 | public boolean isStateful() { 251 | return mFading != null && mFading.isStateful() || mBase != null && mBase.isStateful(); 252 | } 253 | 254 | @Override 255 | public int getAlpha() { 256 | return mAlpha; 257 | } 258 | 259 | @Override 260 | public void setAlpha(int alpha) { 261 | if (alpha != mAlpha) { 262 | mAlpha = alpha; 263 | invalidateSelf(); 264 | } 265 | } 266 | 267 | Drawable getBase() { 268 | return mBase; 269 | } 270 | 271 | Drawable getFading() { 272 | return mFading; 273 | } 274 | 275 | @Override 276 | public int getOpacity() { 277 | return resolveOpacity(mFading == null ? 0 : mFading.getOpacity(), mBase == null ? 0 : mBase.getOpacity()); 278 | } 279 | 280 | // @Override 281 | // public void invalidateDrawable(Drawable who) { 282 | // if ((who == mFading || who == mBase) && getCallback() != null) { 283 | // getCallback().invalidateDrawable(this); 284 | // } 285 | // } 286 | 287 | @Override 288 | public void invalidateDrawable(Drawable who) { 289 | if ((who == mFading || who == mBase)) { 290 | invalidateSelf(); 291 | } 292 | } 293 | 294 | // @Override 295 | // public void scheduleDrawable(Drawable who, Runnable what, long when) { 296 | // if ((who == mFading || who == mBase) && getCallback() != null) { 297 | // getCallback().scheduleDrawable(this, what, when); 298 | // } 299 | // } 300 | 301 | @Override 302 | public void scheduleDrawable(Drawable who, Runnable what, long when) { 303 | if ((who == mFading || who == mBase)) { 304 | scheduleSelf(what, when); 305 | } 306 | } 307 | 308 | @Override 309 | public void unscheduleDrawable(Drawable who, Runnable what) { 310 | if ((who == mFading || who == mBase)) { 311 | unscheduleSelf(what); 312 | } 313 | } 314 | 315 | // @Override 316 | // public void unscheduleDrawable(Drawable who, Runnable what) { 317 | // if ((who == mFading || who == mBase) && getCallback() != null) { 318 | // getCallback().unscheduleDrawable(this, what); 319 | // } 320 | // } 321 | } 322 | -------------------------------------------------------------------------------- /library/src/main/java/me/amiee/nicetab/NiceTabStrip.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Paint; 9 | import android.graphics.Rect; 10 | import android.graphics.RectF; 11 | import android.graphics.Region; 12 | import android.graphics.drawable.ColorDrawable; 13 | import android.graphics.drawable.Drawable; 14 | import android.graphics.drawable.ShapeDrawable; 15 | import android.graphics.drawable.shapes.RoundRectShape; 16 | import android.support.annotation.NonNull; 17 | import android.support.v8.renderscript.Allocation; 18 | import android.support.v8.renderscript.Element; 19 | import android.support.v8.renderscript.RenderScript; 20 | import android.support.v8.renderscript.ScriptIntrinsicBlur; 21 | import android.text.TextPaint; 22 | import android.text.TextUtils; 23 | import android.util.AttributeSet; 24 | import android.util.DisplayMetrics; 25 | import android.util.TypedValue; 26 | import android.view.View; 27 | import android.view.ViewGroup; 28 | 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | 33 | public class NiceTabStrip extends ViewGroup { 34 | private static final boolean DEFAULT_TAB_DISTRIBUTE_EVENLY = false; 35 | private static final boolean DEFAULT_TAB_SELECTED_CENTER = false; 36 | 37 | private static final int DEFAULT_BLUR_RADIUS = 16; 38 | private static final int DEFAULT_DOWN_SAMPLE_FACTOR = 8; 39 | private static final int DEFAULT_OVERLAY_COLOR = 0xaa000000; 40 | 41 | /** 42 | * Indicator underline divider draw order 43 | */ 44 | public enum DrawOrder { 45 | INDICATOR_UNDERLINE_DIVIDER(0), // Default 46 | INDICATOR_DIVIDER_UNDERLINE(1), 47 | UNDERLINE_INDICATOR_DIVIDER(2), 48 | UNDERLINE_DIVIDER_INDICATOR(3), 49 | DIVIDER_INDICATOR_UNDERLINE(4), 50 | DIVIDER_UNDERLINE_INDICATOR(5); 51 | 52 | DrawOrder(int value) { 53 | intValue = value; 54 | } 55 | 56 | static DrawOrder fromInt(int intValue) { 57 | switch (intValue) { 58 | case 0: 59 | return INDICATOR_UNDERLINE_DIVIDER; 60 | case 1: 61 | return INDICATOR_DIVIDER_UNDERLINE; 62 | case 2: 63 | return UNDERLINE_INDICATOR_DIVIDER; 64 | case 3: 65 | return UNDERLINE_DIVIDER_INDICATOR; 66 | case 4: 67 | return DIVIDER_INDICATOR_UNDERLINE; 68 | case 5: 69 | return DIVIDER_UNDERLINE_INDICATOR; 70 | } 71 | return null; 72 | } 73 | 74 | final int intValue; 75 | } 76 | 77 | /** 78 | * Default underline attrs 79 | */ 80 | private static final boolean DEFAULT_SHOW_UNDERLINE = true; 81 | 82 | public enum UnderlineGravity { 83 | TOP(0), 84 | BOTTOM(1); // Default 85 | 86 | UnderlineGravity(int value) { 87 | intValue = value; 88 | } 89 | 90 | static UnderlineGravity fromInt(int intValue) { 91 | switch (intValue) { 92 | case 0: 93 | return TOP; 94 | case 1: 95 | return BOTTOM; 96 | } 97 | return null; 98 | } 99 | 100 | final int intValue; 101 | } 102 | 103 | private static final int DEFAULT_UNDERLINE_COLOR = 0x33000000; 104 | private static final float DEFAULT_UNDERLINE_HEIGHT_DP = 2; 105 | 106 | /** 107 | * Default divider attrs 108 | */ 109 | private static final boolean DEFAULT_SHOW_DIVIDER = true; 110 | private static final int DEFAULT_DIVIDER_COLOR = 0x20000000; 111 | private static final float DEFAULT_DIVIDER_WIDTH_DP = 1; 112 | private static final float DEFAULT_DIVIDER_PADDING_TOP_BOTTOM_DP = 8; 113 | private static final float DEFAULT_DIVIDER_PADDING_LEFT_RIGHT_DP = 0; 114 | 115 | /** 116 | * Default indicator attrs 117 | */ 118 | private static final boolean DEFAULT_SHOW_INDICATOR = true; 119 | 120 | public enum IndicatorGravity { 121 | TOP(0), 122 | CENTER(1), 123 | BOTTOM(2); // Default 124 | 125 | IndicatorGravity(int value) { 126 | intValue = value; 127 | } 128 | 129 | static IndicatorGravity fromInt(int intValue) { 130 | switch (intValue) { 131 | case 0: 132 | return TOP; 133 | case 1: 134 | return CENTER; 135 | case 2: 136 | return BOTTOM; 137 | } 138 | return null; 139 | } 140 | 141 | final int intValue; 142 | } 143 | 144 | private static final int DEFAULT_INDICATOR_COLOR = 0xff33b5e5; 145 | private static final float DEFAULT_INDICATOR_HEIGHT_DP = 8; 146 | private static final float DEFAULT_INDICATOR_CORNER_RADIUS_DP = 0; 147 | private static final float DEFAULT_INDICATOR_PADDING_TOP_BOTTOM_DP = 0; 148 | 149 | /** 150 | * Badge gravity 151 | */ 152 | public enum BadgeGravity { 153 | LEFT(0), 154 | CENTER_LEFT(1), 155 | CENTER_RIGHT(2), 156 | RIGHT(3); // Default 157 | 158 | BadgeGravity(int value) { 159 | intValue = value; 160 | } 161 | 162 | static BadgeGravity fromInt(int intValue) { 163 | switch (intValue) { 164 | case 0: 165 | return LEFT; 166 | case 1: 167 | return CENTER_LEFT; 168 | case 2: 169 | return CENTER_RIGHT; 170 | case 3: 171 | return RIGHT; 172 | } 173 | return null; 174 | } 175 | 176 | final int intValue; 177 | } 178 | 179 | /** 180 | * Default badge attrs 181 | */ 182 | private static final int DEFAULT_BADGE_TEXT_COLOR = 0xffffffff; 183 | private static final int DEFAULT_BADGE_TEXT_SIZE_SP = 10; 184 | private static final int DEFAULT_BADGE_CORNER_RADIUS_DP = 8; 185 | private static final int DEFAULT_BADGE_HEIGHT_DP = 16; 186 | private static final int DEFAULT_BADGE_MIN_WIDTH_DP = 16; 187 | private static final int DEFAULT_BADGE_MAX_WIDTH_DP = 32; 188 | private static final int DEFAULT_BADGE_PADDING_LEFT_RIGHT_DP = 4; 189 | private static final int DEFAULT_BADGE_SMALL_SIZE_DP = 8; 190 | private static final int DEFAULT_BADGE_BACKGROUND_COLOR = 0xffff2600; 191 | 192 | private boolean mTabDistributeEvenly; 193 | private boolean mTabSelectedCenter; 194 | 195 | private View mBlurredView; // if not null, than blur. 196 | private int mBlurredBackgroundColor; // if blurred view's background is null, this will used for blurred background. 197 | private int mBlurRadius; 198 | private int mDownSampleFactor; 199 | private int mOverlayColor; 200 | private int mBlurredViewWidth; 201 | private int mBlurredViewHeight; 202 | private Bitmap mBitmapToBlur; 203 | private Bitmap mBlurredBitmap; 204 | private Canvas mBlurringCanvas; 205 | private RenderScript mRenderScript; 206 | private ScriptIntrinsicBlur mBlurScript; 207 | private Allocation mBlurInput; 208 | private Allocation mBlurOutput; 209 | private boolean mDownSampleFactorChanged; 210 | 211 | private DrawOrder mDrawOrder; 212 | 213 | // @begin underline properties 214 | private boolean mShowUnderline; 215 | private UnderlineGravity mUnderlineGravity; 216 | private int mUnderlineHeight; 217 | private int mUnderlinePaddingTop; 218 | private int mUnderlinePaddingBottom; 219 | private Paint mUnderlinePaint; 220 | // @end underline properties 221 | 222 | // @begin divider properties 223 | private boolean mShowDivider; 224 | private int mDividerWidth; 225 | private int[] mDividerColors; 226 | private int mDividerPaddingTop; 227 | private int mDividerPaddingBottom; 228 | private int mDividerPaddingLeft; 229 | private int mDividerPaddingRight; 230 | private Paint mDividerPaint; 231 | // @end divider properties 232 | 233 | // @begin indicator properties 234 | private boolean mShowIndicator; 235 | private IndicatorGravity mIndicatorGravity; 236 | private int[] mIndicatorColors; 237 | private int mIndicatorHeight; 238 | private float mIndicatorCornerRadius; 239 | private int mIndicatorPaddingTop; 240 | private int mIndicatorPaddingBottom; 241 | private Paint mIndicatorPaint; 242 | // @end indicator properties 243 | 244 | // @begin badge properties 245 | private BadgeGravity mBadgeGravity; 246 | private Drawable mBadgeBackground; 247 | private int mBadgeHeight; 248 | private int mBadgeMinWidth; 249 | private int mBadgeMaxWidth; 250 | private int mBadgeMarginLeft; 251 | private int mBadgeMarginRight; 252 | private int mBadgeMarginTop; 253 | private int mBadgePaddingLeftRight; 254 | private int mBadgeSmallSize; 255 | private TextPaint mBadgeTextPaint; 256 | // @end badge properties 257 | 258 | private int mSelectedPosition; 259 | private float mSelectionOffset; 260 | private int mFirstTabWidth; 261 | private int mLastTabWidth; 262 | private int mTabEvenlyWidth; 263 | private TabStripColorize mTabStripColorize; 264 | private Map mBadgesMap; 265 | 266 | boolean isTabDistributeEvenly() { 267 | return mTabDistributeEvenly; 268 | } 269 | 270 | void setTabDistributeEvenly(boolean tabDistributeEvenly) { 271 | if (tabDistributeEvenly != mTabDistributeEvenly) { 272 | mTabDistributeEvenly = tabDistributeEvenly; 273 | requestLayout(); 274 | } 275 | } 276 | 277 | boolean isTabSelectedCenter() { 278 | return mTabSelectedCenter; 279 | } 280 | 281 | void setTabSelectedCenter(boolean tabSelectedCenter) { 282 | if (tabSelectedCenter != mTabSelectedCenter) { 283 | mTabSelectedCenter = tabSelectedCenter; 284 | requestLayout(); 285 | } 286 | } 287 | 288 | void setDrawOrder(DrawOrder drawOrder) { 289 | if (drawOrder != null && drawOrder != mDrawOrder) { 290 | mDrawOrder = drawOrder; 291 | invalidate(); 292 | } 293 | } 294 | 295 | void setShowUnderline(boolean showUnderline) { 296 | if (showUnderline != mShowUnderline) { 297 | mShowUnderline = showUnderline; 298 | invalidate(); 299 | } 300 | } 301 | 302 | boolean isShowDivider() { 303 | return mShowDivider; 304 | } 305 | 306 | void setShowDivider(boolean showDivider) { 307 | if (showDivider != mShowDivider) { 308 | mShowDivider = showDivider; 309 | requestLayout(); 310 | } 311 | } 312 | 313 | int getDividerWidth() { 314 | return mDividerWidth; 315 | } 316 | 317 | int getDividerPaddingLeft() { 318 | return mDividerPaddingLeft; 319 | } 320 | 321 | int getDividerPaddingRight() { 322 | return mDividerPaddingRight; 323 | } 324 | 325 | void setShowIndicator(boolean showIndicator) { 326 | if (showIndicator != mShowIndicator) { 327 | mShowIndicator = showIndicator; 328 | invalidate(); 329 | } 330 | } 331 | 332 | void setBadge(int position, String text) { 333 | if (position < 0 || position > getChildCount()) { 334 | throw new IllegalArgumentException("Position must between 0 with tabs count."); 335 | } 336 | 337 | if (mBadgesMap == null) { 338 | mBadgesMap = new HashMap<>(); 339 | } 340 | 341 | if (text != null) { 342 | mBadgesMap.put(position, new Badge(text)); 343 | invalidate(); 344 | } 345 | } 346 | 347 | void setBadgeSmall(int position) { 348 | if (position < 0 || position > getChildCount()) { 349 | throw new IllegalArgumentException("Position must between 0 with tabs count."); 350 | } 351 | 352 | if (mBadgesMap == null) { 353 | mBadgesMap = new HashMap<>(); 354 | } 355 | 356 | mBadgesMap.put(position, new Badge()); 357 | invalidate(); 358 | } 359 | 360 | Badge removeBadge(int position) { 361 | if (position < 0 || position > getChildCount()) { 362 | return null; 363 | } 364 | 365 | if (mBadgesMap == null) { 366 | return null; 367 | } 368 | 369 | Badge badge = mBadgesMap.remove(position); 370 | 371 | if (badge != null) { 372 | invalidate(); 373 | } 374 | 375 | return badge; 376 | } 377 | 378 | String getBadgeText(int position) { 379 | return mBadgesMap == null || !mBadgesMap.containsKey(position) ? null : mBadgesMap.get(position).getText(); 380 | } 381 | 382 | void clearBadge() { 383 | if (mBadgesMap != null) { 384 | mBadgesMap.clear(); 385 | invalidate(); 386 | } 387 | } 388 | 389 | int getFirstTabWidth() { 390 | return mFirstTabWidth; 391 | } 392 | 393 | int getLastTabWidth() { 394 | return mLastTabWidth; 395 | } 396 | 397 | int getTabEvenlyWidth() { 398 | return mTabEvenlyWidth; 399 | } 400 | 401 | public NiceTabStrip(Context context) { 402 | this(context, null); 403 | } 404 | 405 | public NiceTabStrip(Context context, AttributeSet attrs) { 406 | super(context); 407 | 408 | setWillNotDraw(false); 409 | 410 | final DisplayMetrics dm = getResources().getDisplayMetrics(); 411 | 412 | final float density = dm.density; 413 | 414 | final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NiceTabLayout); 415 | 416 | // Tab attrs 417 | mTabDistributeEvenly = a.getBoolean(R.styleable.NiceTabLayout_ntlTabDistributeEvenly, DEFAULT_TAB_DISTRIBUTE_EVENLY); 418 | mTabSelectedCenter = a.getBoolean(R.styleable.NiceTabLayout_ntlTabSelectedCenter, DEFAULT_TAB_SELECTED_CENTER); 419 | 420 | mBlurRadius = a.getInt(R.styleable.NiceTabLayout_ntlBlurRadius, DEFAULT_BLUR_RADIUS); 421 | mDownSampleFactor = a.getInt(R.styleable.NiceTabLayout_ntlDownSampleFactor, DEFAULT_DOWN_SAMPLE_FACTOR); 422 | mOverlayColor = a.getInt(R.styleable.NiceTabLayout_ntlOverlayColor, DEFAULT_OVERLAY_COLOR); 423 | 424 | mDrawOrder = DrawOrder.fromInt(a.getInt(R.styleable.NiceTabLayout_ntlDrawOrder, DrawOrder.INDICATOR_UNDERLINE_DIVIDER.intValue)); 425 | 426 | // Underline attrs 427 | mShowUnderline = a.getBoolean(R.styleable.NiceTabLayout_ntlShowUnderline, DEFAULT_SHOW_UNDERLINE); 428 | mUnderlineGravity = UnderlineGravity.fromInt(a.getInt(R.styleable.NiceTabLayout_ntlUnderlineGravity, UnderlineGravity.BOTTOM.intValue)); 429 | final int underlineColor = a.getColor(R.styleable.NiceTabLayout_ntlUnderlineColor, DEFAULT_UNDERLINE_COLOR); 430 | mUnderlineHeight = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlUnderlineHeight, (int) (DEFAULT_UNDERLINE_HEIGHT_DP * density)); 431 | mUnderlinePaddingTop = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlUnderlinePaddingTop, 0); 432 | mUnderlinePaddingBottom = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlUnderlinePaddingBottom, 0); 433 | 434 | mUnderlinePaint = new Paint(); 435 | mUnderlinePaint.setColor(underlineColor); 436 | 437 | // Divider attrs 438 | mShowDivider = a.getBoolean(R.styleable.NiceTabLayout_ntlShowDivider, DEFAULT_SHOW_DIVIDER); 439 | int dividerColor = a.getColor(R.styleable.NiceTabLayout_ntlDividerColor, DEFAULT_DIVIDER_COLOR); 440 | final int dividerColorsId = a.getResourceId(R.styleable.NiceTabLayout_ntlDividerColors, NO_ID); 441 | mDividerColors = (dividerColorsId == NO_ID) ? new int[]{dividerColor} : getResources().getIntArray(dividerColorsId); 442 | mDividerWidth = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlDividerWidth, (int) (DEFAULT_DIVIDER_WIDTH_DP * density)); 443 | final int padding = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlDividerPadding, -1); 444 | mDividerPaddingTop = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlDividerPaddingTop, padding == -1 ? (int) (DEFAULT_DIVIDER_PADDING_TOP_BOTTOM_DP * density) : 0); 445 | mDividerPaddingBottom = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlDividerPaddingBottom, padding == -1 ? (int) (DEFAULT_DIVIDER_PADDING_TOP_BOTTOM_DP * density) : 0); 446 | mDividerPaddingLeft = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlDividerPaddingLeft, padding == -1 ? (int) (DEFAULT_DIVIDER_PADDING_LEFT_RIGHT_DP * density) : 0); 447 | mDividerPaddingRight = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlDividerPaddingRight, padding == -1 ? (int) (DEFAULT_DIVIDER_PADDING_LEFT_RIGHT_DP * density) : 0); 448 | 449 | mDividerPaint = new Paint(); 450 | mDividerPaint.setStrokeWidth(mDividerWidth); 451 | 452 | // Indicator attrs 453 | mShowIndicator = a.getBoolean(R.styleable.NiceTabLayout_ntlShowIndicator, DEFAULT_SHOW_INDICATOR); 454 | mIndicatorGravity = IndicatorGravity.fromInt(a.getInt(R.styleable.NiceTabLayout_ntlIndicatorGravity, IndicatorGravity.BOTTOM.intValue)); 455 | final int indicatorColor = a.getColor(R.styleable.NiceTabLayout_ntlIndicatorColor, DEFAULT_INDICATOR_COLOR); 456 | final int indicatorColorsId = a.getResourceId(R.styleable.NiceTabLayout_ntlIndicatorColors, NO_ID); 457 | mIndicatorColors = (indicatorColorsId == NO_ID) ? new int[]{indicatorColor} : getResources().getIntArray(indicatorColorsId); 458 | mIndicatorHeight = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlIndicatorHeight, (int) (DEFAULT_INDICATOR_HEIGHT_DP * density)); 459 | mIndicatorCornerRadius = a.getDimension(R.styleable.NiceTabLayout_ntlIndicatorCornerRadius, DEFAULT_INDICATOR_CORNER_RADIUS_DP * density); 460 | mIndicatorPaddingTop = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlIndicatorPaddingTop, (int) (DEFAULT_INDICATOR_PADDING_TOP_BOTTOM_DP * density)); 461 | mIndicatorPaddingBottom = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlIndicatorPaddingBottom, (int) (DEFAULT_INDICATOR_PADDING_TOP_BOTTOM_DP * density)); 462 | 463 | mIndicatorPaint = new Paint(); 464 | 465 | // Badge attrs 466 | mBadgeGravity = BadgeGravity.fromInt(a.getInt(R.styleable.NiceTabLayout_ntlBadgeGravity, BadgeGravity.RIGHT.intValue)); 467 | final int badgeTextColor = a.getColor(R.styleable.NiceTabLayout_ntlBadgeTextColor, DEFAULT_BADGE_TEXT_COLOR); 468 | final float badgeTextSize = a.getDimension(R.styleable.NiceTabLayout_ntlBadgeTextSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, DEFAULT_BADGE_TEXT_SIZE_SP, dm)); 469 | mBadgeHeight = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeHeight, (int) (DEFAULT_BADGE_HEIGHT_DP * density)); 470 | final int badgeCornerRadius = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeCornerRadius, (int) (DEFAULT_BADGE_CORNER_RADIUS_DP * density)); 471 | mBadgeMinWidth = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeMinWidth, (int) (DEFAULT_BADGE_MIN_WIDTH_DP * density)); 472 | mBadgeMaxWidth = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeMaxWidth, (int) (DEFAULT_BADGE_MAX_WIDTH_DP * density)); 473 | mBadgeMarginLeft = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeMarginLeft, 0); 474 | mBadgeMarginRight = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeMarginRight, 0); 475 | mBadgeMarginTop = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeMarginTop, 0); 476 | mBadgePaddingLeftRight = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgePaddingLeftRight, (int) (DEFAULT_BADGE_PADDING_LEFT_RIGHT_DP * density)); 477 | mBadgeSmallSize = a.getDimensionPixelSize(R.styleable.NiceTabLayout_ntlBadgeSmallSize, (int) (DEFAULT_BADGE_SMALL_SIZE_DP * density)); 478 | if (a.hasValue(R.styleable.NiceTabLayout_ntlBadgeBackground)) { 479 | Drawable drawable = a.getDrawable(R.styleable.NiceTabLayout_ntlBadgeBackground); 480 | if (drawable instanceof ColorDrawable) { 481 | setUpBadgeBackground(badgeCornerRadius, a.getColor(R.styleable.NiceTabLayout_ntlBadgeBackground, DEFAULT_BADGE_BACKGROUND_COLOR)); 482 | } else { 483 | mBadgeBackground = a.getDrawable(R.styleable.NiceTabLayout_ntlBadgeBackground); 484 | } 485 | } else { 486 | setUpBadgeBackground(badgeCornerRadius, DEFAULT_BADGE_BACKGROUND_COLOR); 487 | } 488 | 489 | mBadgeTextPaint = new TextPaint(); 490 | mBadgeTextPaint.setAntiAlias(true); 491 | mBadgeTextPaint.setColor(badgeTextColor); 492 | mBadgeTextPaint.setTextSize(badgeTextSize); 493 | 494 | a.recycle(); 495 | 496 | if (mDownSampleFactor <= 0) { 497 | throw new IllegalArgumentException("Down sample factor must be greater than 0."); 498 | } 499 | 500 | applyColor(mOverlayColor); 501 | 502 | initRenderScript(context); 503 | 504 | // Setup TabStripColorize 505 | mTabStripColorize = new SimpleTabStripColorize(); 506 | ((SimpleTabStripColorize) mTabStripColorize).setDividerColors(mDividerColors); 507 | ((SimpleTabStripColorize) mTabStripColorize).setIndicatorColors(mIndicatorColors); 508 | } 509 | 510 | void setBlurredView(View blurredView, int blurredBackgroundColor) { 511 | mBlurredView = blurredView; 512 | mBlurredBackgroundColor = blurredBackgroundColor; 513 | } 514 | 515 | void setBlurRadius(int radius) { 516 | mBlurScript.setRadius(radius); 517 | } 518 | 519 | void setDownSampleFactor(int factor) { 520 | if (factor <= 0) { 521 | throw new IllegalArgumentException("Down Sample factor must be greater than 0."); 522 | } 523 | 524 | if (mDownSampleFactor != factor) { 525 | mDownSampleFactor = factor; 526 | mDownSampleFactorChanged = true; 527 | } 528 | } 529 | 530 | void setOverlayColor(int color) { 531 | applyColor(color); 532 | } 533 | 534 | private void applyColor(int color) { 535 | int alpha = Color.alpha(color); 536 | if (alpha > 0xdd) { 537 | mOverlayColor = Color.argb(0xdd, Color.red(color), Color.green(color), Color.blue(color)); 538 | } else { 539 | mOverlayColor = color; 540 | } 541 | } 542 | 543 | private void initRenderScript(Context context) { 544 | mRenderScript = RenderScript.create(context); 545 | mBlurScript = ScriptIntrinsicBlur.create(mRenderScript, Element.U8_4(mRenderScript)); 546 | mBlurScript.setRadius(mBlurRadius); 547 | } 548 | 549 | private void setUpBadgeBackground(float badgeCornerRadius, int color) { 550 | float[] cornerRadius = new float[]{badgeCornerRadius, badgeCornerRadius, badgeCornerRadius, badgeCornerRadius, badgeCornerRadius, badgeCornerRadius, badgeCornerRadius, badgeCornerRadius}; 551 | mBadgeBackground = new ShapeDrawable(new RoundRectShape(cornerRadius, null, null)); 552 | ((ShapeDrawable) mBadgeBackground).getPaint().setColor(color); 553 | } 554 | 555 | void setTabStripColorize(TabStripColorize tabStripColorize) { 556 | if (tabStripColorize != null) { 557 | mTabStripColorize = tabStripColorize; 558 | } else { 559 | mTabStripColorize = new SimpleTabStripColorize(); 560 | ((SimpleTabStripColorize) mTabStripColorize).setDividerColors(mDividerColors); 561 | ((SimpleTabStripColorize) mTabStripColorize).setIndicatorColors(mIndicatorColors); 562 | } 563 | invalidate(); 564 | } 565 | 566 | void setIndicatorColors(int... colors) { 567 | mIndicatorColors = colors; 568 | SimpleTabStripColorize simpleTabStripColorize = new SimpleTabStripColorize(); 569 | simpleTabStripColorize.setIndicatorColors(colors); 570 | simpleTabStripColorize.setDividerColors(mDividerColors); 571 | mTabStripColorize = simpleTabStripColorize; 572 | invalidate(); 573 | } 574 | 575 | void setDividerColors(int... colors) { 576 | mDividerColors = colors; 577 | SimpleTabStripColorize simpleTabStripColorize = new SimpleTabStripColorize(); 578 | simpleTabStripColorize.setIndicatorColors(mIndicatorColors); 579 | simpleTabStripColorize.setDividerColors(colors); 580 | mTabStripColorize = simpleTabStripColorize; 581 | invalidate(); 582 | } 583 | 584 | void onViewPagerPageChanged(int position, float positionOffset) { 585 | mSelectedPosition = position; 586 | mSelectionOffset = positionOffset; 587 | if (mBlurredView != null || mShowIndicator) { 588 | invalidate(); 589 | } 590 | } 591 | 592 | @Override 593 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 594 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 595 | NiceTabLayout tabLayout = ((NiceTabLayout) getParent()); 596 | if (tabLayout.getMeasuredWidth() > 0) { 597 | int maxChildWidth = 0; 598 | int totalChildWidth = 0; 599 | 600 | final int count = getChildCount(); 601 | 602 | for (int i = 0; i < count; i++) { 603 | final View child = getChildAt(i); 604 | measureChild(child, widthMeasureSpec, heightMeasureSpec); 605 | 606 | final int childWidth = child.getMeasuredWidth(); 607 | maxChildWidth = Math.max(maxChildWidth, childWidth); 608 | totalChildWidth += childWidth; 609 | 610 | if (i == 0) { 611 | mFirstTabWidth = childWidth; 612 | } 613 | 614 | if (i == count - 1) { 615 | mLastTabWidth = childWidth; 616 | } 617 | } 618 | 619 | final int totalDividerWidthPadding = mShowDivider ? (count - 1) * (mDividerWidth + mDividerPaddingLeft + mDividerPaddingRight) : 0; 620 | final int parentWidth = tabLayout.getMeasuredWidth() - tabLayout.getCachedPaddingLeft() - tabLayout.getCachedPaddingRight(); 621 | 622 | if (mTabDistributeEvenly) { 623 | totalChildWidth = maxChildWidth * count; 624 | final int childWidth; 625 | 626 | if ((totalChildWidth + totalDividerWidthPadding) > parentWidth) { 627 | childWidth = maxChildWidth; 628 | } else { 629 | if (mTabSelectedCenter) { 630 | childWidth = maxChildWidth; 631 | } else { 632 | childWidth = (parentWidth - totalDividerWidthPadding) / count; 633 | } 634 | } 635 | 636 | mTabEvenlyWidth = childWidth; 637 | 638 | for (int i = 0; i < count; i++) { 639 | final View child = getChildAt(i); 640 | 641 | final int widthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); 642 | final int heightSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY); 643 | 644 | child.measure(widthSpec, heightSpec); 645 | 646 | } 647 | } 648 | 649 | int mTotalWidth = totalChildWidth + totalDividerWidthPadding; 650 | int width = mTotalWidth; 651 | 652 | if (mTotalWidth < tabLayout.getMeasuredWidth()) { 653 | if (mTabSelectedCenter) { 654 | width = mTotalWidth; 655 | tabLayout.setScrollingEnabled(false); 656 | } else { 657 | width = parentWidth; 658 | } 659 | } 660 | 661 | tabLayout.changeTabLayoutPadding(mTabSelectedCenter, mTabDistributeEvenly); 662 | 663 | final int height = resolveSize(0, heightMeasureSpec); 664 | 665 | setMeasuredDimension(width, height); 666 | } 667 | } 668 | 669 | @Override 670 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 671 | final int count = getChildCount(); 672 | 673 | final int parentTop = getPaddingTop(); 674 | final int parentBottom = bottom - top - getPaddingBottom(); 675 | 676 | int childLeft = 0; 677 | final int dividerPaddingWidth = mShowDivider ? mDividerWidth + mDividerPaddingRight + mDividerPaddingLeft : 0; 678 | 679 | for (int i = 0; i < count; i++) { 680 | final View child = getChildAt(i); 681 | final int width = child.getMeasuredWidth(); 682 | final int height = child.getMeasuredHeight(); 683 | 684 | child.layout(childLeft, parentTop, childLeft + width, Math.min(parentTop + height, parentBottom)); 685 | childLeft += (width + dividerPaddingWidth); 686 | } 687 | } 688 | 689 | @Override 690 | protected void onDraw(Canvas canvas) { 691 | drawBlurBackground(canvas); 692 | 693 | switch (mDrawOrder) { 694 | case INDICATOR_UNDERLINE_DIVIDER: { 695 | drawIndicator(canvas); 696 | drawUnderline(canvas); 697 | drawDivider(canvas); 698 | break; 699 | } 700 | case INDICATOR_DIVIDER_UNDERLINE: { 701 | drawIndicator(canvas); 702 | drawDivider(canvas); 703 | drawUnderline(canvas); 704 | break; 705 | } 706 | case UNDERLINE_INDICATOR_DIVIDER: { 707 | drawUnderline(canvas); 708 | drawIndicator(canvas); 709 | drawDivider(canvas); 710 | break; 711 | } 712 | case UNDERLINE_DIVIDER_INDICATOR: { 713 | drawUnderline(canvas); 714 | drawDivider(canvas); 715 | drawIndicator(canvas); 716 | break; 717 | } 718 | case DIVIDER_INDICATOR_UNDERLINE: { 719 | drawDivider(canvas); 720 | drawIndicator(canvas); 721 | drawUnderline(canvas); 722 | break; 723 | } 724 | case DIVIDER_UNDERLINE_INDICATOR: { 725 | drawDivider(canvas); 726 | drawUnderline(canvas); 727 | drawIndicator(canvas); 728 | break; 729 | } 730 | default: { 731 | drawIndicator(canvas); 732 | drawUnderline(canvas); 733 | drawDivider(canvas); 734 | break; 735 | } 736 | } 737 | } 738 | 739 | @Override 740 | protected void onDetachedFromWindow() { 741 | super.onDetachedFromWindow(); 742 | if (mRenderScript != null) { 743 | mRenderScript.destroy(); 744 | } 745 | } 746 | 747 | private void drawBlurBackground(Canvas canvas) { 748 | if (mBlurredView != null) { 749 | if (prepare()) { 750 | if (mBlurredBackgroundColor != 0) { 751 | mBitmapToBlur.eraseColor(mBlurredBackgroundColor); 752 | } 753 | mBlurredView.draw(mBlurringCanvas); 754 | blur(); 755 | 756 | NiceTabLayout tabLayout = (NiceTabLayout) getParent(); 757 | 758 | if (tabLayout != null) { 759 | final int pPaddingLeft = tabLayout.getPaddingLeft(); 760 | final int pPaddingRight = tabLayout.getPaddingRight(); 761 | 762 | canvas.save(); 763 | 764 | if (tabLayout.getPaddingLeft() != 0 || tabLayout.getPaddingRight() != 0) { 765 | // allow drawing out of bounds 766 | Rect clipBounds = canvas.getClipBounds(); 767 | clipBounds.inset(-(pPaddingLeft + pPaddingRight), 0); 768 | canvas.clipRect(clipBounds, Region.Op.REPLACE); 769 | } 770 | 771 | canvas.translate(mBlurredView.getLeft() - getLeft() + tabLayout.getScrollX(), mBlurredView.getTop() - getTop()); 772 | canvas.scale(mDownSampleFactor, mDownSampleFactor); 773 | canvas.drawBitmap(mBlurredBitmap, 0, 0, null); 774 | canvas.drawColor(mOverlayColor); 775 | canvas.restore(); 776 | } 777 | } 778 | } 779 | } 780 | 781 | protected boolean prepare() { 782 | final int width = mBlurredView.getWidth(); 783 | final int height = mBlurredView.getHeight(); 784 | 785 | if (mBlurringCanvas == null || mDownSampleFactorChanged 786 | || mBlurredViewWidth != width || mBlurredViewHeight != height) { 787 | mDownSampleFactorChanged = false; 788 | 789 | mBlurredViewWidth = width; 790 | mBlurredViewHeight = height; 791 | 792 | int scaledWidth = width / mDownSampleFactor; 793 | int scaledHeight = height / mDownSampleFactor; 794 | 795 | // The following manipulation is to avoid some RenderScript artifacts at the edge. 796 | scaledWidth = scaledWidth - scaledWidth % 4 + 4; 797 | scaledHeight = scaledHeight - scaledHeight % 4 + 4; 798 | 799 | if (mBlurredBitmap == null 800 | || mBlurredBitmap.getWidth() != scaledWidth 801 | || mBlurredBitmap.getHeight() != scaledHeight) { 802 | mBitmapToBlur = Bitmap.createBitmap(scaledWidth, scaledHeight, 803 | Bitmap.Config.ARGB_8888); 804 | if (mBitmapToBlur == null) { 805 | return false; 806 | } 807 | 808 | mBlurredBitmap = Bitmap.createBitmap(scaledWidth, scaledHeight, 809 | Bitmap.Config.ARGB_8888); 810 | if (mBlurredBitmap == null) { 811 | return false; 812 | } 813 | } 814 | 815 | mBlurringCanvas = new Canvas(mBitmapToBlur); 816 | mBlurringCanvas.scale(1f / mDownSampleFactor, 1f / mDownSampleFactor); 817 | mBlurInput = Allocation.createFromBitmap(mRenderScript, mBitmapToBlur, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); 818 | mBlurOutput = Allocation.createTyped(mRenderScript, mBlurInput.getType()); 819 | } 820 | return true; 821 | } 822 | 823 | protected void blur() { 824 | mBlurInput.copyFrom(mBitmapToBlur); 825 | mBlurScript.setInput(mBlurInput); 826 | mBlurScript.forEach(mBlurOutput); 827 | mBlurOutput.copyTo(mBlurredBitmap); 828 | } 829 | 830 | /** 831 | * Draw indicator 832 | * 833 | * @param canvas The canvas 834 | */ 835 | private void drawIndicator(Canvas canvas) { 836 | if (mShowIndicator) { 837 | final int height = getHeight(); 838 | final int childCount = getChildCount(); 839 | 840 | if (childCount > 0) { 841 | View tabView = getChildAt(mSelectedPosition); 842 | int left = tabView.getLeft(); 843 | int right = tabView.getRight(); 844 | int color = mTabStripColorize.getIndicatorColor(mSelectedPosition); 845 | 846 | if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { 847 | int nextColor = mTabStripColorize.getIndicatorColor(mSelectedPosition + 1); 848 | if (color != nextColor) { 849 | color = ColorUtils.blendColors(nextColor, color, mSelectionOffset); 850 | } 851 | 852 | // Draw the selection partway between the tabs 853 | View nextTabView = getChildAt(mSelectedPosition + 1); 854 | left = (int) (mSelectionOffset * nextTabView.getLeft() + (1.0f - mSelectionOffset) * left); 855 | right = (int) (mSelectionOffset * nextTabView.getRight() + (1.0f - mSelectionOffset) * right); 856 | } 857 | 858 | mIndicatorPaint.setColor(color); 859 | 860 | RectF rectF = new RectF(left, height - mIndicatorHeight - mIndicatorPaddingBottom, right, height - mIndicatorPaddingBottom); 861 | switch (mIndicatorGravity) { 862 | case TOP: { 863 | rectF.set(left, mIndicatorPaddingTop, right, mIndicatorHeight + mIndicatorPaddingTop); 864 | break; 865 | } 866 | case CENTER: { 867 | rectF.set(left, (height - mIndicatorHeight) / 2, right, (height + mIndicatorHeight) / 2); 868 | break; 869 | } 870 | } 871 | 872 | if (mIndicatorCornerRadius > 0f) { 873 | mIndicatorPaint.setAntiAlias(true); 874 | canvas.drawRoundRect(rectF, mIndicatorCornerRadius, mIndicatorCornerRadius, mIndicatorPaint); 875 | } else { 876 | mIndicatorPaint.setAntiAlias(false); 877 | canvas.drawRect(rectF, mIndicatorPaint); 878 | } 879 | 880 | if (mOnIndicatorColorChangedListener != null) { 881 | mOnIndicatorColorChangedListener.onIndicatorColorChanged((NiceTabLayout) this.getParent(), color); 882 | } 883 | } 884 | } 885 | } 886 | 887 | /** 888 | * Draw underline 889 | * 890 | * @param canvas The canvas 891 | */ 892 | private void drawUnderline(Canvas canvas) { 893 | if (mShowUnderline) { 894 | View parent = (View) getParent(); 895 | if (parent != null && (parent.getPaddingLeft() != 0 || parent.getPaddingRight() != 0)) { 896 | final int pPaddingLeft = parent.getPaddingLeft(); 897 | final int pPaddingRight = parent.getPaddingRight(); 898 | 899 | canvas.save(); 900 | 901 | // allow drawing out of bounds 902 | Rect clipBounds = canvas.getClipBounds(); 903 | clipBounds.inset(-(pPaddingLeft + pPaddingRight), 0); 904 | canvas.clipRect(clipBounds, Region.Op.REPLACE); 905 | 906 | if (mUnderlineGravity == UnderlineGravity.TOP) { 907 | // If on top ignore bottom padding 908 | canvas.drawRect(-pPaddingLeft, mUnderlinePaddingTop, getWidth() + pPaddingLeft + pPaddingRight, mUnderlineHeight + mUnderlinePaddingTop, mUnderlinePaint); 909 | } else { 910 | // If on bottom ignore top padding 911 | canvas.drawRect(-pPaddingLeft, getHeight() - mUnderlineHeight - mUnderlinePaddingBottom, getWidth() + pPaddingLeft + pPaddingRight, getHeight() - mUnderlinePaddingBottom, mUnderlinePaint); 912 | } 913 | 914 | canvas.restore(); 915 | } else { 916 | if (mUnderlineGravity == UnderlineGravity.TOP) { 917 | // If on top ignore bottom padding 918 | canvas.drawRect(0, mUnderlinePaddingTop, getWidth(), mUnderlineHeight + mUnderlinePaddingTop, mUnderlinePaint); 919 | } else { 920 | // If on bottom ignore top padding 921 | canvas.drawRect(0, getHeight() - mUnderlineHeight - mUnderlinePaddingBottom, getWidth(), getHeight() - mUnderlinePaddingBottom, mUnderlinePaint); 922 | } 923 | } 924 | } 925 | } 926 | 927 | /** 928 | * Draw divider 929 | * 930 | * @param canvas The canvas 931 | */ 932 | private void drawDivider(Canvas canvas) { 933 | if (mShowDivider) { 934 | final int childCount = getChildCount(); 935 | final int height = getHeight() - mDividerPaddingTop - mDividerPaddingBottom; 936 | 937 | for (int i = 0; i < childCount - 1; i++) { 938 | final View child = getChildAt(i); 939 | mDividerPaint.setColor(mTabStripColorize.getDividerColor(i)); 940 | canvas.drawLine(child.getRight() + mDividerPaddingLeft, mDividerPaddingTop, child.getRight() + mDividerPaddingLeft, 941 | mDividerPaddingTop + height, mDividerPaint); 942 | } 943 | } 944 | } 945 | 946 | @Override 947 | protected void dispatchDraw(@NonNull Canvas canvas) { 948 | super.dispatchDraw(canvas); 949 | drawBadge(canvas); 950 | } 951 | 952 | /** 953 | * Draw badge 954 | * 955 | * @param canvas The canvas 956 | */ 957 | private void drawBadge(Canvas canvas) { 958 | if (mBadgesMap != null && !mBadgesMap.isEmpty()) { 959 | int badgeLeft = 0, badgeRight = 0, badgeBottom, badgeWidth; 960 | int badgeHeight; 961 | float textWidth = 0, textHeight = 0; 962 | Rect textBounds = new Rect(); 963 | 964 | for (int i : mBadgesMap.keySet()) { 965 | final View child = getChildAt(i); 966 | final Badge badge = mBadgesMap.get(i); 967 | String text = badge.getText(); 968 | 969 | if (badge.isSmall()) { 970 | badgeWidth = mBadgeSmallSize; 971 | badgeHeight = mBadgeSmallSize; 972 | } else { 973 | badgeHeight = mBadgeHeight; 974 | if (text != null) { 975 | mBadgeTextPaint.getTextBounds(text, 0, text.length(), textBounds); 976 | textWidth = mBadgeTextPaint.measureText(text); // Use measureText to calculate width 977 | textHeight = textBounds.height(); // Use height from getTextBounds() 978 | } else { 979 | textWidth = 0; 980 | textHeight = 0; 981 | } 982 | 983 | if (textWidth > 0) { 984 | if (textWidth > (mBadgeMaxWidth - mBadgePaddingLeftRight * 2)) { 985 | textWidth = mBadgeMaxWidth - mBadgePaddingLeftRight * 2; 986 | text = TextUtils.ellipsize(text, mBadgeTextPaint, textWidth, TextUtils.TruncateAt.END).toString(); 987 | badgeWidth = mBadgeMaxWidth; 988 | } else { 989 | badgeWidth = Math.max(Math.round((mBadgePaddingLeftRight * 2) + textWidth), mBadgeMinWidth); 990 | } 991 | } else { 992 | badgeWidth = mBadgeMinWidth; 993 | } 994 | } 995 | 996 | badgeBottom = mBadgeMarginTop + badgeHeight; 997 | 998 | switch (mBadgeGravity) { 999 | case LEFT: { 1000 | badgeLeft = child.getLeft() + mBadgeMarginLeft; 1001 | badgeRight = badgeLeft + badgeWidth; 1002 | break; 1003 | } 1004 | case CENTER_LEFT: { 1005 | final int center = child.getRight() - child.getMeasuredWidth() / 2; 1006 | badgeRight = center - mBadgeMarginRight; 1007 | badgeLeft = badgeRight - badgeWidth; 1008 | break; 1009 | } 1010 | case CENTER_RIGHT: { 1011 | final int center = child.getRight() - child.getMeasuredWidth() / 2; 1012 | badgeLeft = center + mBadgeMarginLeft; 1013 | badgeRight = badgeLeft + badgeWidth; 1014 | break; 1015 | } 1016 | case RIGHT: { 1017 | badgeRight = child.getRight() - mBadgeMarginRight; 1018 | badgeLeft = badgeRight - badgeWidth; 1019 | break; 1020 | } 1021 | } 1022 | 1023 | mBadgeBackground.setBounds(badgeLeft, mBadgeMarginTop, badgeRight, badgeBottom); 1024 | mBadgeBackground.draw(canvas); 1025 | 1026 | if (text != null && textWidth > 0) { 1027 | canvas.drawText(text, mBadgeBackground.getBounds().centerX() - (textWidth / 2f), mBadgeBackground.getBounds().centerY() + (textHeight / 2f), mBadgeTextPaint); 1028 | } 1029 | } 1030 | } 1031 | } 1032 | 1033 | /** 1034 | * Allows complete control over the colors in the tab layout. Set with 1035 | * {@link #setTabStripColorize(TabStripColorize)}. 1036 | */ 1037 | public interface TabStripColorize { 1038 | 1039 | /** 1040 | * @return return the color of the indicator used when {@code position} is selected. 1041 | */ 1042 | int getIndicatorColor(int position); 1043 | 1044 | /** 1045 | * @return return the color of the divider drawn to the right of {@code position}. 1046 | */ 1047 | int getDividerColor(int position); 1048 | } 1049 | 1050 | private static class SimpleTabStripColorize implements TabStripColorize { 1051 | private int[] mIndicatorColors; 1052 | private int[] mDividerColors; 1053 | 1054 | @Override 1055 | public final int getIndicatorColor(int position) { 1056 | return mIndicatorColors[position % mIndicatorColors.length]; 1057 | } 1058 | 1059 | @Override 1060 | public final int getDividerColor(int position) { 1061 | return mDividerColors[position % mDividerColors.length]; 1062 | } 1063 | 1064 | void setIndicatorColors(int... colors) { 1065 | mIndicatorColors = colors; 1066 | } 1067 | 1068 | void setDividerColors(int... colors) { 1069 | mDividerColors = colors; 1070 | } 1071 | } 1072 | 1073 | private OnIndicatorColorChangedListener mOnIndicatorColorChangedListener; 1074 | 1075 | void setOnIndicatorColorChangedListener(OnIndicatorColorChangedListener onIndicatorColorChangedListener) { 1076 | mOnIndicatorColorChangedListener = onIndicatorColorChangedListener; 1077 | } 1078 | 1079 | /** 1080 | * Allows get current indicator color. Set with 1081 | * {@link me.amiee.nicetab.NiceTabLayout#setOnIndicatorColorChangedListener(OnIndicatorColorChangedListener)}. 1082 | */ 1083 | public interface OnIndicatorColorChangedListener { 1084 | void onIndicatorColorChanged(NiceTabLayout tabLayout, int color); 1085 | } 1086 | } 1087 | -------------------------------------------------------------------------------- /library/src/main/java/me/amiee/nicetab/StateListDrawableHelper.java: -------------------------------------------------------------------------------- 1 | package me.amiee.nicetab; 2 | 3 | 4 | import android.graphics.drawable.Drawable; 5 | import android.graphics.drawable.StateListDrawable; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | public class StateListDrawableHelper { 10 | private static final Method METHOD_GET_STATE_COUNT; 11 | private static final Method METHOD_GET_STATE_SET; 12 | private static final Method METHOD_GET_STATE_DRAWABLE; 13 | private static final Method METHOD_GET_STATE_DRAWABLE_INDEX; 14 | 15 | static { 16 | Method getStateCount = null, 17 | getStateSet = null, 18 | getStateDrawable = null, 19 | getStateDrawableIndex = null; 20 | 21 | Class cls = StateListDrawable.class; 22 | 23 | try { 24 | getStateCount = cls.getDeclaredMethod("getStateCount"); 25 | getStateSet = cls.getDeclaredMethod("getStateSet", int.class); 26 | getStateDrawable = cls.getDeclaredMethod("getStateDrawable", int.class); 27 | getStateDrawableIndex = cls.getDeclaredMethod("getStateDrawableIndex", int[].class); 28 | } catch (NoSuchMethodException e) { 29 | e.printStackTrace(); 30 | } 31 | 32 | METHOD_GET_STATE_COUNT = getStateCount; 33 | METHOD_GET_STATE_SET = getStateSet; 34 | METHOD_GET_STATE_DRAWABLE = getStateDrawable; 35 | METHOD_GET_STATE_DRAWABLE_INDEX = getStateDrawableIndex; 36 | } 37 | 38 | private StateListDrawableHelper() { 39 | } 40 | 41 | public static int getStateCount(StateListDrawable drawable) { 42 | try { 43 | return (int) METHOD_GET_STATE_COUNT.invoke(drawable); 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | return 0; 47 | } 48 | } 49 | 50 | public static int[] getStateSet(StateListDrawable drawable, int index) { 51 | try { 52 | return (int[]) METHOD_GET_STATE_SET.invoke(drawable, index); 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | return new int[0]; 56 | } 57 | } 58 | 59 | public static Drawable getStateDrawable(StateListDrawable drawable, int index) { 60 | try { 61 | return (Drawable) METHOD_GET_STATE_DRAWABLE.invoke(drawable, index); 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | return null; 65 | } 66 | } 67 | 68 | public static int getStateDrawableIndex(StateListDrawable drawable, int[] stateSet) { 69 | try { 70 | return (int) METHOD_GET_STATE_DRAWABLE_INDEX.invoke(drawable, (Object) stateSet); 71 | } catch (Exception e) { 72 | e.printStackTrace(); 73 | return -1; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /maven_push.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven' 2 | apply plugin: 'signing' 3 | 4 | def isReleaseBuild() { 5 | return VERSION_NAME.contains("SNAPSHOT") == false 6 | } 7 | 8 | def sonatypeRepositoryUrl 9 | if (isReleaseBuild()) { 10 | println 'RELEASE BUILD' 11 | sonatypeRepositoryUrl = hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL 12 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 13 | } else { 14 | println 'SNAPSHOT BUILD' 15 | sonatypeRepositoryUrl = hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL 16 | : "https://oss.sonatype.org/content/repositories/snapshots/" 17 | 18 | } 19 | 20 | def getRepositoryUsername() { 21 | return hasProperty('nexusUsername') ? nexusUsername : "" 22 | } 23 | 24 | def getRepositoryPassword() { 25 | return hasProperty('nexusPassword') ? nexusPassword : "" 26 | } 27 | 28 | afterEvaluate { project -> 29 | uploadArchives { 30 | repositories { 31 | mavenDeployer { 32 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 33 | 34 | pom.artifactId = POM_ARTIFACT_ID 35 | 36 | repository(url: sonatypeRepositoryUrl) { 37 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) 38 | } 39 | 40 | pom.project { 41 | name POM_NAME 42 | groupId POM_GROUP_ID 43 | version VERSION_NAME 44 | packaging POM_PACKAGING 45 | description POM_DESCRIPTION 46 | url POM_URL 47 | inceptionYear POM_INCEPTION_YEAR 48 | 49 | scm { 50 | url POM_SCM_URL 51 | connection POM_SCM_CONNECTION 52 | developerConnection POM_SCM_DEV_CONNECTION 53 | } 54 | 55 | licenses { 56 | license { 57 | name POM_LICENCE_NAME 58 | url POM_LICENCE_URL 59 | distribution POM_LICENCE_DIST 60 | } 61 | } 62 | 63 | developers { 64 | developer { 65 | id POM_DEVELOPER_ID 66 | name POM_DEVELOPER_NAME 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | signing { 75 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } 76 | sign configurations.archives 77 | } 78 | 79 | task androidJavadocs(type: Javadoc) { 80 | failOnError false 81 | source = android.sourceSets.main.java.source 82 | options { 83 | links "http://docs.oracle.com/javase/7/docs/api/" 84 | linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference" 85 | } 86 | classpath += project.android.libraryVariants.toList().first().javaCompile.classpath 87 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 88 | } 89 | 90 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { 91 | classifier = 'javadoc' 92 | //basename = artifact_id 93 | from androidJavadocs.destinationDir 94 | } 95 | 96 | task androidSourcesJar(type: Jar) { 97 | classifier = 'sources' 98 | from android.sourceSets.main.java.srcDirs 99 | } 100 | 101 | artifacts { 102 | //archives packageReleaseJar 103 | archives androidSourcesJar 104 | archives androidJavadocsJar 105 | } 106 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':demo', ':library' 2 | --------------------------------------------------------------------------------