├── .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 | 
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 |
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 |
--------------------------------------------------------------------------------