7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_sample_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/my.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/color1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/color2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/color3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/color4.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_rect.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_dialer_idle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_dialer_call.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_dialer.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/color.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/my_activity2.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_elevation_sample.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_navigation_drawer.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/translate_down_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 16dp
6 | 16dp
7 |
8 |
9 | 56dp
10 | 2dp
11 | 4dp
12 | 240dp
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/activities/ElevationSampleActivity.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.activities;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.Menu;
6 | import android.view.MenuItem;
7 |
8 | import com.saulmm.material.R;
9 |
10 | public class ElevationSampleActivity extends Activity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_elevation_sample);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/nav_drawer.xml:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/translate_down_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/utils/AnimatorAdapter.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.utils;
2 |
3 | import android.animation.Animator;
4 |
5 | public class AnimatorAdapter implements Animator.AnimatorListener {
6 | @Override
7 | public void onAnimationStart(Animator animation) {
8 |
9 | }
10 |
11 | @Override
12 | public void onAnimationEnd(Animator animation) {
13 |
14 | }
15 |
16 | @Override
17 | public void onAnimationCancel(Animator animation) {
18 |
19 | }
20 |
21 | @Override
22 | public void onAnimationRepeat(Animator animation) {
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 22
5 | buildToolsVersion "20.0.0"
6 |
7 | defaultConfig {
8 | applicationId "com.saulmm.material.myapplication"
9 | minSdkVersion 21
10 | targetSdkVersion 22
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 |
15 | }
16 |
17 | dependencies {
18 | compile fileTree(dir: 'libs', include: ['*.jar'])
19 | compile 'com.android.support:cardview-v7:21.0.0'
20 | compile 'com.android.support:appcompat-v7:22.0.0'
21 | compile 'com.android.support:support-v4:22.0.0'
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/fragments/NavigationFragment.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.fragments;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import com.saulmm.material.R;
10 |
11 |
12 | public class NavigationFragment extends Fragment {
13 |
14 | @Override
15 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
16 |
17 | return inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
18 | }
19 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_dialer_sample_page.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_fab_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Android generated
2 | bin
3 | gen
4 | lint.xml
5 | lint
6 |
7 | #Eclipse
8 | .project
9 | .classpath
10 | .settings
11 | .checkstyle
12 |
13 | #IntelliJ IDEA
14 | .idea
15 | *.iml
16 | *.ipr
17 | *.iws
18 | classes
19 | gen-external-apklibs
20 |
21 | #gradle
22 | .gradle
23 | build/
24 |
25 | #vi
26 | *.swp
27 |
28 | #other editors
29 | *.bak
30 |
31 | #Maven
32 | target
33 | release.properties
34 | pom.xml.*
35 |
36 | #Ant
37 | build.xml
38 | ant.properties
39 | local.properties
40 | proguard.cfg
41 | proguard-project.txt
42 |
43 | #Other
44 | .DS_Store
45 | Thumbs.db
46 | tmp
47 | *.tgz
48 | *.lock
49 | *.lck
50 | com_crashlytics_export_strings.xml
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/fragments/SamplePageFragment.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.fragments;
2 |
3 | import android.app.Fragment;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | import com.saulmm.material.R;
11 |
12 | public class SamplePageFragment extends Fragment {
13 |
14 | @Nullable
15 | @Override
16 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
17 |
18 | View rootView = inflater.inflate(R.layout.fragment_dialer_sample_page, container);
19 |
20 | return rootView;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Applications/Android Studio.app/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 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/utils/TransitionAdapter.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.utils;
2 |
3 | import android.transition.Transition;
4 |
5 | public class TransitionAdapter implements Transition.TransitionListener {
6 |
7 | @Override
8 | public void onTransitionStart(Transition transition) {
9 |
10 | }
11 |
12 | @Override
13 | public void onTransitionEnd(Transition transition) {
14 |
15 | }
16 |
17 | @Override
18 | public void onTransitionCancel(Transition transition) {
19 |
20 | }
21 |
22 | @Override
23 | public void onTransitionPause(Transition transition) {
24 |
25 | }
26 |
27 | @Override
28 | public void onTransitionResume(Transition transition) {
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/translation_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
13 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/app/src/main/res/anim/fab_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
13 |
14 |
15 |
18 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | My Application
5 | Settings
6 | MyActivity2
7 | Example action
8 | NavDrawerActivity
9 | ColorActivity
10 | Open
11 | Close
12 |
13 |
14 |
15 | 1
16 | 2
17 | 3
18 | 4
19 | 5
20 | 6
21 | 7
22 | 8
23 | 9
24 | *
25 | 0
26 | #
27 |
28 |
29 | ElevationSampleActivity
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_dialer_sliding.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #F48FB1
6 | #EC407A
7 | #2A2A2A
8 | #EEFF41
9 | #ff515252
10 |
11 |
12 |
13 | #00C853
14 | #0277BD
15 | #0288D1
16 | #FFF
17 |
18 |
19 | #4fc3f7
20 | #009688
21 |
22 | #42bd41
23 | #673AB7
24 |
25 | #ffb74d
26 | #E91E63
27 |
28 | #ff8a65
29 | #d500f9
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/views/adapters/SamplePagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.views.adapters;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.PagerAdapter;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import com.saulmm.material.R;
10 |
11 | @SuppressWarnings("FieldCanBeLocal")
12 | public class SamplePagerAdapter extends PagerAdapter {
13 |
14 | private final String [] TITLES = {"SPEED DIAL", "RECENTS", "CONTACTS"};
15 | private final int FRAGMENT_COUNT = 3;
16 | private Context context;
17 |
18 | public SamplePagerAdapter(Context context) {
19 | this.context = context;
20 | }
21 |
22 | @Override
23 | public int getCount() {
24 | return FRAGMENT_COUNT;
25 | }
26 |
27 | @Override
28 | public boolean isViewFromObject(View view, Object o) {
29 | return o == view;
30 | }
31 |
32 |
33 | @Override
34 | public CharSequence getPageTitle(int position) {
35 | return TITLES[position];
36 | }
37 |
38 | @Override
39 | public Object instantiateItem(ViewGroup container, int position) {
40 |
41 | View view = LayoutInflater.from(context).inflate(
42 | R.layout.fragment_dialer_sample_page,
43 | container, false);
44 |
45 | container.addView(view);
46 | return view;
47 | }
48 |
49 | @Override
50 | public void destroyItem(ViewGroup container, int position, Object object) {
51 | container.removeView((View) object);
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_sliding.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
15 |
19 |
20 |
25 |
26 |
30 |
31 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/activities/DialerSampleActivity.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.saulmm.material.activities;
4 |
5 | import android.graphics.Point;
6 | import android.os.Bundle;
7 | import android.support.v4.view.ViewPager;
8 | import android.support.v7.app.ActionBarActivity;
9 | import android.support.v7.widget.Toolbar;
10 | import android.view.Display;
11 | import android.view.View;
12 | import android.view.animation.Animation;
13 | import android.view.animation.AnimationUtils;
14 | import android.widget.ArrayAdapter;
15 | import android.widget.FrameLayout;
16 | import android.widget.GridView;
17 | import android.widget.ImageButton;
18 |
19 | import com.saulmm.material.R;
20 | import com.saulmm.material.utils.GUIUtils;
21 | import com.saulmm.material.views.adapters.SamplePagerAdapter;
22 | import com.saulmm.material.views.widgets.SlidingTabLayout;
23 |
24 | public class DialerSampleActivity extends ActionBarActivity {
25 |
26 | private int screenWidth;
27 | private ImageButton fabButton;
28 | private FrameLayout dialerKeysContainer;
29 | private float absolutefabPosition;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 |
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.activity_dialer);
36 |
37 | configureToolbar();
38 | }
39 |
40 | private void configureToolbar() {
41 |
42 | Toolbar mainToolbar = (Toolbar) findViewById(R.id.activity_dialer_toolbar);
43 | mainToolbar.setTitleTextColor(getResources().getColor(R.color.theme_dialer_accent));
44 | setSupportActionBar(mainToolbar);
45 | getSupportActionBar().setTitle("Dialer");
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/activities/TransitionFirstActivity.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.activities;
2 |
3 | import android.app.Activity;
4 | import android.app.ActivityOptions;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.transition.Slide;
8 | import android.util.Pair;
9 | import android.view.Gravity;
10 | import android.view.View;
11 |
12 | import com.saulmm.material.R;
13 |
14 | public class TransitionFirstActivity extends Activity {
15 |
16 | private View mFabButton;
17 | private View mHeader;
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 |
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_transition_first);
24 |
25 | mFabButton = findViewById(R.id.fab_button);
26 | mHeader = findViewById(R.id.activity_transition_header);
27 |
28 | Slide slideExitTransition = new Slide(Gravity.BOTTOM);
29 | slideExitTransition.excludeTarget(android.R.id.navigationBarBackground, true);
30 | slideExitTransition.excludeTarget(android.R.id.statusBarBackground, true);
31 | slideExitTransition.excludeTarget(R.id.activity_transition_header, true);
32 | getWindow().setExitTransition(slideExitTransition);
33 | }
34 |
35 | public void onFabPressed(View view) {
36 |
37 | Intent i = new Intent (TransitionFirstActivity.this,
38 | TransitionSecondActivity.class);
39 |
40 | ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(
41 | TransitionFirstActivity.this,Pair.create(mFabButton, "fab"), Pair.create(mHeader, "holder1"));
42 |
43 | startActivity(i, transitionActivityOptions.toBundle());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/fragments/SlidingTabFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.saulmm.material.fragments;
18 |
19 |
20 | import android.app.Fragment;
21 | import android.os.Bundle;
22 | import android.support.v4.view.ViewPager;
23 | import android.view.LayoutInflater;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 |
27 | import com.saulmm.material.R;
28 | import com.saulmm.material.views.adapters.SamplePagerAdapter;
29 | import com.saulmm.material.views.widgets.SlidingTabLayout;
30 |
31 |
32 | public class SlidingTabFragment extends Fragment {
33 |
34 | static final String LOG_TAG = "SlidingTabsBasicFragment";
35 |
36 | @Override
37 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
38 |
39 | return inflater.inflate(R.layout.fragment_dialer_sliding, container, false);
40 | }
41 |
42 | @Override
43 | public void onViewCreated(View view, Bundle savedInstanceState) {
44 |
45 | ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
46 | mViewPager.setAdapter(new SamplePagerAdapter(getActivity()));
47 |
48 | SlidingTabLayout mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
49 | mSlidingTabLayout.setViewPager(mViewPager);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Working with shared elements
2 |
3 | Commit - [**8872619**](https://github.com/saulmm/Android-Material-Examples/commit/8872619ba751d99044a8426a35e6d2416d3af286)
4 |
5 | 
6 |
7 | ### Working with shared elements, explode transition, and animations
8 |
9 | Commit - [**901d62c**](https://github.com/saulmm/Android-Material-Examples/commit/901d62c65bbe70f55d944b718b8e6c6c2c69839d)
10 |
11 | 
12 |
13 | ## Playing with the new menu-to arrow toggle animattion added in the Support Library
14 |
15 | Commit - [**ead8ada**](https://github.com/saulmm/Android-Material-Examples/commit/ead8adaafb482bd29a9ef86568a08afebeffd043)
16 |
17 | 
18 |
19 | ## Reusing an example to build a pretty effect like the tab slide of google play app
20 |
21 | Commit - [**f502305**](https://github.com/saulmm/Android-Material-Examples/commit/f5023057d1e088cc69849c9c7f60d32279604214)
22 |
23 | 
24 |
25 | ## Using CircularReveal to show a pretty effect between activities
26 |
27 | Commit - [**ba9c202**](https://github.com/saulmm/Android-Material-Examples/commit/ba9c2026bbe5fc57d6166389f60030176d065623)
28 |
29 | 
30 |
31 | ## Replicating some parts of the lollypop dialer app basing on the material design principle: Motion provides meaning
32 |
33 | Commit - [**eb20707**](https://github.com/saulmm/Android-Material-Examples/commit/eb20707d8db3aef321ae30cb80faada5e3cd7b4d)
34 |
35 | 
36 |
37 |
38 | ## Using StateListAnimator to change the elevation of a view smootly
39 |
40 | Commit - [**3f1102b**](https://github.com/saulmm/Android-Material-Examples/commit/3f1102b50606d2b57781ad5c0de232697da47862)
41 |
42 | 
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_elevation_sample.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
16 |
17 |
25 |
26 |
36 |
37 |
47 |
48 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_transition_second.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
16 |
17 |
28 |
29 |
32 |
33 |
36 |
37 |
40 |
41 |
44 |
45 |
48 |
49 |
52 |
53 |
54 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_dialer.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
13 |
14 |
21 |
22 |
27 |
28 |
34 |
35 |
43 |
44 |
45 |
46 |
56 |
57 |
66 |
67 |
68 |
69 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/activities/TransitionSecondActivity.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.activities;
2 |
3 | import android.animation.Animator;
4 | import android.app.Activity;
5 | import android.os.Bundle;
6 | import android.transition.Slide;
7 | import android.transition.Transition;
8 | import android.view.Gravity;
9 | import android.view.View;
10 | import android.view.ViewPropertyAnimator;
11 | import android.widget.LinearLayout;
12 |
13 | import com.saulmm.material.R;
14 | import com.saulmm.material.utils.AnimatorAdapter;
15 | import com.saulmm.material.utils.TransitionAdapter;
16 |
17 | public class TransitionSecondActivity extends Activity {
18 |
19 | private static final int SCALE_DELAY = 30;
20 | private LinearLayout rowContainer;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 |
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_transition_second);
27 |
28 | rowContainer = (LinearLayout) findViewById(R.id.row_container2);
29 |
30 | Slide slideExitTransition = new Slide(Gravity.BOTTOM);
31 | slideExitTransition.excludeTarget(android.R.id.navigationBarBackground, true);
32 | slideExitTransition.excludeTarget(android.R.id.statusBarBackground, true);
33 |
34 |
35 | getWindow().getEnterTransition().addListener(new TransitionAdapter() {
36 |
37 | @Override
38 | public void onTransitionEnd(Transition transition) {
39 |
40 | super.onTransitionEnd(transition);
41 |
42 | getWindow().getEnterTransition().removeListener(this);
43 |
44 | for (int i = 0; i < rowContainer.getChildCount(); i++) {
45 |
46 | View rowView = rowContainer.getChildAt(i);
47 | rowView.animate().setStartDelay(i * SCALE_DELAY)
48 | .scaleX(1).scaleY(1);
49 | }
50 | }
51 | });
52 | }
53 |
54 | @Override
55 | public void onBackPressed() {
56 |
57 | for (int i = 0; i < rowContainer.getChildCount(); i++) {
58 |
59 | View rowView = rowContainer.getChildAt(i);
60 |
61 | ViewPropertyAnimator propertyAnimator = rowView.animate()
62 | .setStartDelay(i * SCALE_DELAY)
63 | .scaleX(0).scaleY(0)
64 | .setListener(new AnimatorAdapter() {
65 |
66 | @Override
67 | public void onAnimationEnd(Animator animation) {
68 |
69 | super.onAnimationEnd(animation);
70 | finishAfterTransition();
71 | }
72 | });
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_transition_first.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
16 |
17 |
32 |
33 |
40 |
41 |
49 |
50 |
58 |
59 |
65 |
66 |
71 |
72 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
18 |
19 |
24 |
25 |
30 |
31 |
36 |
37 |
42 |
43 |
48 |
49 |
54 |
55 |
59 |
60 |
64 |
65 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/utils/GUIUtils.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.utils;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.content.Context;
6 | import android.graphics.Outline;
7 | import android.transition.Fade;
8 | import android.view.View;
9 | import android.view.ViewAnimationUtils;
10 | import android.view.ViewPropertyAnimator;
11 | import android.view.Window;
12 | import android.view.animation.PathInterpolator;
13 |
14 | import com.saulmm.material.R;
15 |
16 | public class GUIUtils {
17 |
18 | public static final int SCALE_FACTOR = 30;
19 |
20 | public static void configureWindowEnterExitExplodeTransition(Window w) {
21 |
22 | Fade ex = new Fade();
23 | ex.setInterpolator(new PathInterpolator(0.4f, 0, 1, 1));
24 | ex.setDuration(5000);
25 | w.setExitTransition(ex);
26 | w.setEnterTransition(ex);
27 | }
28 |
29 | public static void configureFab (View fabButton) {
30 |
31 | int fabSize = fabButton.getContext().getResources()
32 | .getDimensionPixelSize(R.dimen.fab_size);
33 | Outline fabOutLine = new Outline();
34 | fabOutLine.setOval(0, 0, fabSize, fabSize);
35 | }
36 |
37 | public static int getStatusBarHeight(Context c) {
38 |
39 | int result = 0;
40 | int resourceId = c.getResources().getIdentifier("status_bar_height", "dimen", "android");
41 | if (resourceId > 0) {
42 | result = c.getResources().getDimensionPixelSize(resourceId);
43 | }
44 | return result;
45 | }
46 |
47 |
48 | public static void hideRevealEffect (final View v, int centerX, int centerY, int initialRadius) {
49 |
50 | v.setVisibility(View.VISIBLE);
51 |
52 | // create the animation (the final radius is zero)
53 | Animator anim = ViewAnimationUtils.createCircularReveal(
54 | v, centerX, centerY, initialRadius, 0);
55 |
56 | anim.setDuration(350);
57 |
58 | // make the view invisible when the animation is done
59 | anim.addListener(new AnimatorListenerAdapter() {
60 | @Override
61 | public void onAnimationEnd(Animator animation) {
62 | super.onAnimationEnd(animation);
63 | v.setVisibility(View.INVISIBLE);
64 | }
65 | });
66 |
67 | anim.start();
68 | }
69 |
70 | public static void showRevealEffect(final View v, int centerX, int centerY, Animator.AnimatorListener lis) {
71 |
72 | v.setVisibility(View.VISIBLE);
73 |
74 | int height = v.getHeight();
75 |
76 | Animator anim = ViewAnimationUtils.createCircularReveal(
77 | v, centerX, centerY, 0, height);
78 |
79 | anim.setDuration(350);
80 |
81 | anim.addListener(lis);
82 | anim.start();
83 | }
84 |
85 |
86 |
87 | public static void hideViewByScale(View view) {
88 |
89 | ViewPropertyAnimator propertyAnimator = view.animate().setStartDelay(SCALE_FACTOR)
90 | .scaleX(0).scaleY(0);
91 |
92 | propertyAnimator.start();
93 | }
94 |
95 | public static void showViewByScale(View view) {
96 |
97 | ViewPropertyAnimator propertyAnimator = view.animate().setStartDelay(SCALE_FACTOR)
98 | .scaleX(1).scaleY(1);
99 |
100 | propertyAnimator.start();
101 | }
102 |
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/activities/SlidingActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.saulmm.material.activities;
18 |
19 | import android.app.FragmentTransaction;
20 | import android.content.res.Configuration;
21 | import android.os.Bundle;
22 | import android.support.v4.widget.DrawerLayout;
23 | import android.support.v7.app.ActionBarActivity;
24 | import android.support.v7.app.ActionBarDrawerToggle;
25 | import android.support.v7.widget.Toolbar;
26 | import android.view.Gravity;
27 | import android.view.MenuItem;
28 | import android.view.View;
29 |
30 | import com.saulmm.material.R;
31 | import com.saulmm.material.fragments.SlidingTabFragment;
32 |
33 | public class SlidingActivity extends ActionBarActivity {
34 |
35 | private DrawerLayout mDrawerLayout;
36 | private ActionBarDrawerToggle mDrawerToggle;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_sliding);
42 |
43 | if (savedInstanceState == null) {
44 | FragmentTransaction transaction = getFragmentManager().beginTransaction();
45 | SlidingTabFragment fragment = new SlidingTabFragment();
46 | transaction.replace(R.id.sample_content_fragment, fragment);
47 | transaction.commit();
48 | }
49 |
50 | configureToolbar();
51 | configureDrawer();
52 | }
53 |
54 | private void configureToolbar() {
55 | Toolbar mainToolbar = (Toolbar) findViewById(R.id.activity_transition_header);
56 | setSupportActionBar(mainToolbar);
57 | getSupportActionBar().setTitle("Sliding");
58 |
59 | mainToolbar.setNavigationOnClickListener(new View.OnClickListener() {
60 | @Override
61 | public void onClick(View view) {
62 |
63 | if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
64 | mDrawerLayout.closeDrawer(Gravity.START);
65 |
66 | } else {
67 | mDrawerLayout.openDrawer(Gravity.START);
68 | }
69 | }
70 | });
71 | }
72 |
73 | private void configureDrawer() {
74 | // Configure drawer
75 | mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
76 |
77 | mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
78 | R.string.drawer_open,
79 | R.string.drawer_closed) {
80 |
81 | public void onDrawerClosed(View view) {
82 | supportInvalidateOptionsMenu();
83 | }
84 |
85 | public void onDrawerOpened(View drawerView) {
86 | supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
87 | }
88 | };
89 |
90 | mDrawerLayout.setDrawerListener(mDrawerToggle);
91 | }
92 |
93 | @Override
94 | public boolean onOptionsItemSelected(MenuItem item) {
95 |
96 | if (mDrawerToggle.onOptionsItemSelected(item)) {
97 | return true;
98 | }
99 |
100 | return super.onOptionsItemSelected(item);
101 | }
102 |
103 | @Override
104 | protected void onPostCreate(Bundle savedInstanceState) {
105 | super.onPostCreate(savedInstanceState);
106 | mDrawerToggle.syncState();
107 | }
108 |
109 | @Override
110 | public void onConfigurationChanged(Configuration newConfig) {
111 | super.onConfigurationChanged(newConfig);
112 | mDrawerToggle.onConfigurationChanged(newConfig);
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/activities/ColorActivity.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.material.activities;
2 |
3 | import android.animation.Animator;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.SharedPreferences;
8 | import android.os.Bundle;
9 | import android.util.TypedValue;
10 | import android.view.View;
11 | import android.widget.CheckBox;
12 | import android.widget.CompoundButton;
13 | import android.widget.Switch;
14 |
15 | import com.saulmm.material.R;
16 | import com.saulmm.material.utils.GUIUtils;
17 |
18 | public class ColorActivity extends Activity {
19 |
20 | private SharedPreferences sharedpreferences;
21 | private View revealView;
22 |
23 | @Override
24 | protected void onCreate(final Bundle savedInstanceState) {
25 |
26 | super.onCreate(savedInstanceState);
27 |
28 | // Set the saved theme
29 | sharedpreferences = getSharedPreferences("test", Context.MODE_PRIVATE);
30 | setTheme(sharedpreferences.getInt("theme", R.style.AppTheme));
31 |
32 | setContentView(R.layout.activity_color);
33 |
34 | // Views
35 | Switch themeSwitch = (Switch) findViewById(R.id.theme_switch);
36 | themeSwitch.setChecked(sharedpreferences.getBoolean(themeSwitch.getId()+"", false));
37 | themeSwitch.setOnCheckedChangeListener(checkedListener);
38 |
39 | CheckBox themeCheck = (CheckBox) findViewById(R.id.theme_check);
40 | themeCheck.setChecked(sharedpreferences.getBoolean(themeCheck.getId()+"", false));
41 | themeCheck.setOnCheckedChangeListener(checkedListener);
42 |
43 | revealView = findViewById(R.id.reveal_view);
44 |
45 | // Show the unReveal effect
46 | final int cx = sharedpreferences.getInt("x", 0);
47 | final int cy = sharedpreferences.getInt("y", 0);
48 |
49 | startHideRevealEffect(cx, cy);
50 | }
51 |
52 | private void startHideRevealEffect(final int cx, final int cy) {
53 |
54 | if (cx != 0 && cy != 0) {
55 | // Show the unReveal effect when the view is attached to the window
56 | revealView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
57 | @Override
58 | public void onViewAttachedToWindow(View v) {
59 |
60 | // Get the accent color
61 | TypedValue outValue = new TypedValue();
62 | getTheme().resolveAttribute(android.R.attr.colorPrimary, outValue, true);
63 | revealView.setBackgroundColor(outValue.data);
64 |
65 | GUIUtils.hideRevealEffect(revealView, cx, cy, 1920);
66 | }
67 |
68 | @Override
69 | public void onViewDetachedFromWindow(View v) {}
70 | });
71 | }
72 | }
73 |
74 |
75 | private void hideNavigationStatus() {
76 |
77 | View decorView = getWindow().getDecorView();
78 |
79 | int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
80 | decorView.setSystemUiVisibility(uiOptions);
81 | }
82 |
83 |
84 | Animator.AnimatorListener revealAnimationListener = new Animator.AnimatorListener() {
85 |
86 | @Override
87 | public void onAnimationStart(Animator animation) {}
88 |
89 | @Override
90 | public void onAnimationEnd(Animator animation) {
91 |
92 | Intent i = new Intent(ColorActivity.this, ColorActivity.class);
93 | i.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
94 | startActivity(i);
95 | overridePendingTransition(0, 0);
96 | finish();
97 | }
98 |
99 | @Override
100 | public void onAnimationCancel(Animator animation) {}
101 |
102 | @Override
103 | public void onAnimationRepeat(Animator animation) {}
104 | };
105 |
106 |
107 | public void view(View view) {
108 |
109 | int selectedTheme = 0;
110 | int primaryColor = 0;
111 |
112 | switch (view.getId()) {
113 | case R.id.circle1:
114 | selectedTheme = R.style.theme1;
115 | primaryColor = getResources().getColor(R.color.color_set_1_primary);
116 | break;
117 |
118 | case R.id.circle2:
119 | selectedTheme = R.style.theme2;
120 | primaryColor = getResources().getColor(R.color.color_set_2_primary);
121 | break;
122 |
123 | case R.id.circle3:
124 | selectedTheme = R.style.theme3;
125 | primaryColor = getResources().getColor(R.color.color_set_3_primary);
126 | break;
127 |
128 | case R.id.circle4:
129 | selectedTheme = R.style.theme4;
130 | primaryColor = getResources().getColor(R.color.color_set_4_primary);
131 | break;
132 | }
133 |
134 | int [] location = new int[2];
135 | revealView.setBackgroundColor(primaryColor);
136 | view.getLocationOnScreen(location);
137 |
138 | int cx = (location[0] + (view.getWidth() / 2));
139 | int cy = location[1] + (GUIUtils.getStatusBarHeight(this) / 2);
140 |
141 | SharedPreferences.Editor ed = sharedpreferences.edit();
142 | ed.putInt("x", cx);
143 | ed.putInt("y", cy);
144 | ed.putInt("theme", selectedTheme);
145 | ed.apply();
146 |
147 | hideNavigationStatus();
148 | GUIUtils.showRevealEffect(revealView, cx, cy, revealAnimationListener);
149 | }
150 |
151 |
152 | CompoundButton.OnCheckedChangeListener checkedListener = new CompoundButton.OnCheckedChangeListener() {
153 |
154 | @Override
155 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
156 | SharedPreferences.Editor ed = sharedpreferences.edit();
157 | ed.putInt("theme", (isChecked) ? R.style.Base_Theme_AppCompat : R.style.Base_Theme_AppCompat_Light);
158 | ed.putBoolean(buttonView.getId()+"", isChecked);
159 | ed.apply();
160 | }
161 | };
162 | }
163 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_color.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
15 |
16 |
22 |
23 |
33 |
34 |
41 |
42 |
50 |
51 |
52 |
53 |
60 |
61 |
67 |
68 |
69 |
74 |
75 |
81 |
82 |
89 |
90 |
91 |
92 |
98 |
99 |
105 |
106 |
113 |
114 |
121 |
122 |
123 |
124 |
131 |
132 |
142 |
143 |
153 |
154 |
164 |
165 |
174 |
175 |
176 |
177 |
178 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabStrip.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.saulmm.material.views.widgets;
18 |
19 | import android.R;
20 | import android.content.Context;
21 | import android.graphics.Canvas;
22 | import android.graphics.Color;
23 | import android.graphics.Paint;
24 | import android.util.AttributeSet;
25 | import android.util.TypedValue;
26 | import android.view.View;
27 | import android.widget.LinearLayout;
28 |
29 | class SlidingTabStrip extends LinearLayout {
30 |
31 | private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
32 | private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
33 | private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3;
34 | private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
35 |
36 | private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
37 | private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
38 | private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
39 |
40 | private final int mBottomBorderThickness;
41 | private final Paint mBottomBorderPaint;
42 |
43 | private final int mSelectedIndicatorThickness;
44 | private final Paint mSelectedIndicatorPaint;
45 |
46 | private final int mDefaultBottomBorderColor;
47 |
48 | private final Paint mDividerPaint;
49 | private final float mDividerHeight;
50 |
51 | private int mSelectedPosition;
52 | private float mSelectionOffset;
53 |
54 | private SlidingTabLayout.TabColorizer mCustomTabColorizer;
55 | private final SimpleTabColorizer mDefaultTabColorizer;
56 |
57 | SlidingTabStrip(Context context) {
58 | this(context, null);
59 | }
60 |
61 | SlidingTabStrip(Context context, AttributeSet attrs) {
62 | super(context, attrs);
63 | setWillNotDraw(false);
64 |
65 | final float density = getResources().getDisplayMetrics().density;
66 |
67 | TypedValue outValue = new TypedValue();
68 | context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
69 | final int themeForegroundColor = outValue.data;
70 |
71 | TypedValue backgroundValue = new TypedValue();
72 | context.getTheme().resolveAttribute(R.attr.colorPrimary, outValue, true);
73 | final int themeBackground = outValue.data;
74 |
75 | TypedValue accentValue = new TypedValue();
76 | context.getTheme().resolveAttribute(R.attr.colorAccent, outValue, true);
77 | final int accentColor = outValue.data;
78 |
79 | mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
80 | DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
81 |
82 | mDefaultTabColorizer = new SimpleTabColorizer();
83 | mDefaultTabColorizer.setIndicatorColors(accentColor);
84 | mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
85 | DEFAULT_DIVIDER_COLOR_ALPHA));
86 |
87 | mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
88 | mBottomBorderPaint = new Paint();
89 | mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
90 |
91 | mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
92 | mSelectedIndicatorPaint = new Paint();
93 |
94 | mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
95 | mDividerPaint = new Paint();
96 | mDividerPaint.setStrokeWidth((int) (0));
97 |
98 | setBackgroundColor(themeBackground);
99 | }
100 |
101 | void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
102 | mCustomTabColorizer = customTabColorizer;
103 | invalidate();
104 | }
105 |
106 | void setSelectedIndicatorColors(int... colors) {
107 | // Make sure that the custom colorizer is removed
108 | mCustomTabColorizer = null;
109 | mDefaultTabColorizer.setIndicatorColors(colors);
110 | invalidate();
111 | }
112 |
113 | void setDividerColors(int... colors) {
114 | // Make sure that the custom colorizer is removed
115 | mCustomTabColorizer = null;
116 | mDefaultTabColorizer.setDividerColors(colors);
117 | invalidate();
118 | }
119 |
120 | void onViewPagerPageChanged(int position, float positionOffset) {
121 | mSelectedPosition = position;
122 | mSelectionOffset = positionOffset;
123 | invalidate();
124 | }
125 |
126 | @Override
127 | protected void onDraw(Canvas canvas) {
128 | final int height = getHeight();
129 | final int childCount = getChildCount();
130 | final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
131 | final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
132 | ? mCustomTabColorizer
133 | : mDefaultTabColorizer;
134 |
135 | // Thick colored underline below the current selection
136 | if (childCount > 0) {
137 | View selectedTitle = getChildAt(mSelectedPosition);
138 | int left = selectedTitle.getLeft();
139 | int right = selectedTitle.getRight();
140 | int color = tabColorizer.getIndicatorColor(mSelectedPosition);
141 |
142 | if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
143 | int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
144 | if (color != nextColor) {
145 | color = blendColors(nextColor, color, mSelectionOffset);
146 | }
147 |
148 | // Draw the selection partway between the tabs
149 | View nextTitle = getChildAt(mSelectedPosition + 1);
150 | left = (int) (mSelectionOffset * nextTitle.getLeft() +
151 | (1.0f - mSelectionOffset) * left);
152 | right = (int) (mSelectionOffset * nextTitle.getRight() +
153 | (1.0f - mSelectionOffset) * right);
154 | }
155 |
156 | mSelectedIndicatorPaint.setColor(color);
157 |
158 | canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
159 | height, mSelectedIndicatorPaint);
160 | }
161 |
162 | // Thin underline along the entire bottom edge
163 | canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
164 |
165 | // Vertical separators between the titles
166 | int separatorTop = (height - dividerHeightPx) / 2;
167 | for (int i = 0; i < childCount - 1; i++) {
168 | View child = getChildAt(i);
169 | mDividerPaint.setColor(tabColorizer.getDividerColor(i));
170 | canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
171 | separatorTop + dividerHeightPx, mDividerPaint);
172 | }
173 | }
174 |
175 | /**
176 | * Set the alpha value of the {@code color} to be the given {@code alpha} value.
177 | */
178 | private static int setColorAlpha(int color, byte alpha) {
179 | return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
180 | }
181 |
182 | /**
183 | * Blend {@code color1} and {@code color2} using the given ratio.
184 | *
185 | * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
186 | * 0.0 will return {@code color2}.
187 | */
188 | private static int blendColors(int color1, int color2, float ratio) {
189 | final float inverseRation = 1f - ratio;
190 | float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
191 | float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
192 | float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
193 | return Color.rgb((int) r, (int) g, (int) b);
194 | }
195 |
196 | private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
197 | private int[] mIndicatorColors;
198 | private int[] mDividerColors;
199 |
200 | @Override
201 | public final int getIndicatorColor(int position) {
202 | return mIndicatorColors[position % mIndicatorColors.length];
203 | }
204 |
205 | @Override
206 | public final int getDividerColor(int position) {
207 | return mDividerColors[position % mDividerColors.length];
208 | }
209 |
210 | void setIndicatorColors(int... colors) {
211 | mIndicatorColors = colors;
212 | }
213 |
214 | void setDividerColors(int... colors) {
215 | mDividerColors = colors;
216 | }
217 | }
218 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/material/views/widgets/SlidingTabLayout.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.saulmm.material.views.widgets;
18 |
19 | import android.content.Context;
20 | import android.graphics.Typeface;
21 | import android.os.Build;
22 | import android.support.v4.view.PagerAdapter;
23 | import android.support.v4.view.ViewPager;
24 | import android.util.AttributeSet;
25 | import android.util.TypedValue;
26 | import android.view.Gravity;
27 | import android.view.LayoutInflater;
28 | import android.view.View;
29 | import android.widget.HorizontalScrollView;
30 | import android.widget.TextView;
31 |
32 | import com.saulmm.material.R;
33 |
34 | import java.util.ArrayList;
35 |
36 | /**
37 | * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
38 | * the user's scroll progress.
39 | *
40 | * To use the component, simply add it to your view hierarchy. Then in your
41 | * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
42 | * {@link #setViewPager(android.support.v4.view.ViewPager)} providing it the ViewPager this layout is being used for.
43 | *
44 | * The colors can be customized in two ways. The first and simplest is to provide an array of colors
45 | * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
46 | * alternative is via the {@link SlidingTabLayout.TabColorizer} interface which provides you complete control over
47 | * which color is used for any individual position.
48 | *
49 | * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
50 | * providing the layout ID of your custom layout.
51 | */
52 | public class SlidingTabLayout extends HorizontalScrollView {
53 |
54 | /**
55 | * Allows complete control over the colors drawn in the tab layout. Set with
56 | * {@link #setCustomTabColorizer(SlidingTabLayout.TabColorizer)}.
57 | */
58 | public interface TabColorizer {
59 |
60 | /**
61 | * @return return the color of the indicator used when {@code position} is selected.
62 | */
63 | int getIndicatorColor(int position);
64 |
65 | /**
66 | * @return return the color of the divider drawn to the right of {@code position}.
67 | */
68 | int getDividerColor(int position);
69 |
70 | }
71 |
72 | private static final int TITLE_OFFSET_DIPS = 24;
73 | private static final int TAB_VIEW_PADDING_DIPS = 16;
74 | private static final int TAB_VIEW_TEXT_SIZE_SP = 14;
75 |
76 | private int mTitleOffset;
77 |
78 | private int mTabViewLayoutId;
79 | private int mTabViewTextViewId;
80 |
81 | private ViewPager mViewPager;
82 | private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
83 |
84 | private ArrayList pagerListeners = new ArrayList();
85 |
86 | private final SlidingTabStrip mTabStrip;
87 |
88 | public SlidingTabLayout(Context context) {
89 | this(context, null);
90 | }
91 |
92 | public SlidingTabLayout(Context context, AttributeSet attrs) {
93 | this(context, attrs, 0);
94 | }
95 |
96 | public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
97 | super(context, attrs, defStyle);
98 |
99 | // Disable the Scroll Bar
100 | setHorizontalScrollBarEnabled(false);
101 | // Make sure that the Tab Strips fills this View
102 | setFillViewport(true);
103 |
104 | mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
105 |
106 | mTabStrip = new SlidingTabStrip(context);
107 | addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
108 |
109 | pagerListeners.add(new InternalViewPagerListener());
110 | }
111 |
112 | public void addPagerListener (ViewPager.OnPageChangeListener listener) {
113 | pagerListeners.add(listener);
114 | }
115 |
116 | /**
117 | * Set the custom {@link SlidingTabLayout.TabColorizer} to be used.
118 | *
119 | * If you only require simple custmisation then you can use
120 | * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
121 | * similar effects.
122 | */
123 | public void setCustomTabColorizer(TabColorizer tabColorizer) {
124 | mTabStrip.setCustomTabColorizer(tabColorizer);
125 | }
126 |
127 | /**
128 | * Sets the colors to be used for indicating the selected tab. These colors are treated as a
129 | * circular array. Providing one color will mean that all tabs are indicated with the same color.
130 | */
131 | public void setSelectedIndicatorColors(int... colors) {
132 | mTabStrip.setSelectedIndicatorColors(colors);
133 | }
134 |
135 | /**
136 | * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
137 | * Providing one color will mean that all tabs are indicated with the same color.
138 | */
139 | public void setDividerColors(int... colors) {
140 | mTabStrip.setDividerColors(colors);
141 | }
142 |
143 | /**
144 | * Set the {@link android.support.v4.view.ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
145 | * required to set any {@link android.support.v4.view.ViewPager.OnPageChangeListener} through this method. This is so
146 | * that the layout can update it's scroll position correctly.
147 | *
148 | * @see android.support.v4.view.ViewPager#setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener)
149 | */
150 | public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
151 | mViewPagerPageChangeListener = listener;
152 | }
153 |
154 | /**
155 | * Set the custom layout to be inflated for the tab views.
156 | *
157 | * @param layoutResId Layout id to be inflated
158 | * @param textViewId id of the {@link android.widget.TextView} in the inflated view
159 | */
160 | public void setCustomTabView(int layoutResId, int textViewId) {
161 | mTabViewLayoutId = layoutResId;
162 | mTabViewTextViewId = textViewId;
163 | }
164 |
165 | /**
166 | * Sets the associated view pager. Note that the assumption here is that the pager content
167 | * (number of tabs and tab titles) does not change after this call has been made.
168 | */
169 | public void setViewPager(ViewPager viewPager) {
170 | mTabStrip.removeAllViews();
171 |
172 | mViewPager = viewPager;
173 | if (viewPager != null) {
174 | viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
175 | @Override
176 | public void onPageScrolled(int i, float v, int i2) {
177 |
178 | for (ViewPager.OnPageChangeListener pagerListener : pagerListeners) {
179 | pagerListener.onPageScrolled(i, v, i2);
180 | }
181 | }
182 |
183 | @Override
184 | public void onPageSelected(int i) {
185 | for (ViewPager.OnPageChangeListener pagerListener : pagerListeners) {
186 | pagerListener.onPageSelected(i);
187 | }
188 | }
189 |
190 | @Override
191 | public void onPageScrollStateChanged(int i) {
192 | for (ViewPager.OnPageChangeListener pagerListener : pagerListeners) {
193 | pagerListener.onPageScrollStateChanged(i);
194 | }
195 | }
196 | });
197 | populateTabStrip();
198 | }
199 | }
200 |
201 | /**
202 | * Create a default view to be used for tabs. This is called if a custom tab view is not set via
203 | * {@link #setCustomTabView(int, int)}.
204 | */
205 | protected TextView createDefaultTabView(Context context) {
206 | TextView textView = new TextView(context);
207 | textView.setGravity(Gravity.CENTER);
208 | textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
209 | textView.setTypeface(Typeface.DEFAULT_BOLD);
210 | textView.setTextAppearance(context, R.style.SlidingTextViewStyle);
211 |
212 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
213 | // If we're running on Honeycomb or newer, then we can use the Theme's
214 | // selectableItemBackground to ensure that the View has a pressed state
215 | TypedValue outValue = new TypedValue();
216 | getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
217 | outValue, true);
218 | textView.setBackgroundResource(outValue.resourceId);
219 | }
220 |
221 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
222 | // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
223 | textView.setAllCaps(true);
224 | }
225 |
226 | int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
227 | textView.setPadding(padding, padding, padding, padding);
228 |
229 | return textView;
230 | }
231 |
232 | private void populateTabStrip() {
233 | final PagerAdapter adapter = mViewPager.getAdapter();
234 | final OnClickListener tabClickListener = new TabClickListener();
235 |
236 | for (int i = 0; i < adapter.getCount(); i++) {
237 | View tabView = null;
238 | TextView tabTitleView = null;
239 |
240 | if (mTabViewLayoutId != 0) {
241 | // If there is a custom tab view layout id set, try and inflate it
242 | tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
243 | false);
244 | tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
245 | }
246 |
247 | if (tabView == null) {
248 | tabView = createDefaultTabView(getContext());
249 | }
250 |
251 | if (tabTitleView == null && TextView.class.isInstance(tabView)) {
252 | tabTitleView = (TextView) tabView;
253 | }
254 |
255 | tabTitleView.setText(adapter.getPageTitle(i));
256 | tabView.setOnClickListener(tabClickListener);
257 |
258 | mTabStrip.addView(tabView);
259 | }
260 | }
261 |
262 | @Override
263 | protected void onAttachedToWindow() {
264 | super.onAttachedToWindow();
265 |
266 | if (mViewPager != null) {
267 | scrollToTab(mViewPager.getCurrentItem(), 0);
268 | }
269 | }
270 |
271 | private void scrollToTab(int tabIndex, int positionOffset) {
272 | final int tabStripChildCount = mTabStrip.getChildCount();
273 | if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
274 | return;
275 | }
276 |
277 | View selectedChild = mTabStrip.getChildAt(tabIndex);
278 | if (selectedChild != null) {
279 | int targetScrollX = selectedChild.getLeft() + positionOffset;
280 |
281 | if (tabIndex > 0 || positionOffset > 0) {
282 | // If we're not at the first child and are mid-scroll, make sure we obey the offset
283 | targetScrollX -= mTitleOffset;
284 | }
285 |
286 | scrollTo(targetScrollX, 0);
287 | }
288 | }
289 |
290 | private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
291 | private int mScrollState;
292 |
293 | @Override
294 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
295 | int tabStripChildCount = mTabStrip.getChildCount();
296 | if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
297 | return;
298 | }
299 |
300 | mTabStrip.onViewPagerPageChanged(position, positionOffset);
301 |
302 | View selectedTitle = mTabStrip.getChildAt(position);
303 | int extraOffset = (selectedTitle != null)
304 | ? (int) (positionOffset * selectedTitle.getWidth())
305 | : 0;
306 | scrollToTab(position, extraOffset);
307 |
308 | if (mViewPagerPageChangeListener != null) {
309 | mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
310 | positionOffsetPixels);
311 | }
312 | }
313 |
314 | @Override
315 | public void onPageScrollStateChanged(int state) {
316 | mScrollState = state;
317 |
318 | if (mViewPagerPageChangeListener != null) {
319 | mViewPagerPageChangeListener.onPageScrollStateChanged(state);
320 | }
321 | }
322 |
323 | @Override
324 | public void onPageSelected(int position) {
325 | if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
326 | mTabStrip.onViewPagerPageChanged(position, 0f);
327 | scrollToTab(position, 0);
328 | }
329 |
330 | if (mViewPagerPageChangeListener != null) {
331 | mViewPagerPageChangeListener.onPageSelected(position);
332 | }
333 | }
334 |
335 | }
336 |
337 | private class TabClickListener implements OnClickListener {
338 | @Override
339 | public void onClick(View v) {
340 | for (int i = 0; i < mTabStrip.getChildCount(); i++) {
341 | if (v == mTabStrip.getChildAt(i)) {
342 | mViewPager.setCurrentItem(i);
343 | return;
344 | }
345 | }
346 | }
347 | }
348 |
349 | }
350 |
--------------------------------------------------------------------------------