Android Sliding Tabs – раздвижные вкладки в стиле Material Design

Как вы могли заметить, Google обновил многие из своих приложений в стиле Material Design. Одним из основных визуальных изменений в обновления является обновленные раздвижные вкладки. Google дает хорошие руководящие принципы по разработке приложений с вкладками (узнать больше), но не спешит обновлять документацию. В этом учебном пособии я покажу вам, как создать Android приложение с табами – раздвижными вкладками в материальном стиле.

Приступая к работе

1. Добавьте библиотеки appcompat-v7.21.0.+ и appcompat-v4.21.0.+ в файл сборки build.gradle вашего проекта:

[pastacode lang=”java” message=” build.gradle” highlight=”” provider=”manual”]

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.1"

    defaultConfig {
        applicationId "samples.exoguru.materialtabs"
        minSdkVersion 16
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.android.support:support-v4:21.0.3'
} 

[/pastacode]

2. Так как Google не обновил их документацию, нам придется украсть два java-файла из открытого исходного кода приложения Google I/O  и вставим его в наш пакет java, чтобы наши вкладки выглядели так же, как в обновленных приложениях Google apps. Вы можете получить эти файлы с ссылке ниже:

SlidingTabLayout.java
SlidingTabStrip.java

3. Создайте новый файл с именем colors.xml в папке ресурсов и добавьте следующий код:

[pastacode lang=”bash” message=”colors.xml” highlight=”” provider=”manual”]



    #00897B
    #00695C
    #004D40

[/pastacode]

4. Создайте новый файл в вашей папке res/color/ и присвойте ему имя selector.xml. После этого добавьте следующий код в него. Этот XML-код изменяет цвет текста активной вкладки, позже мы увидим связанный код стороне Java.

[pastacode lang=”java” message=”selector.xml” highlight=”” provider=”manual”]



     
     
     
     

[/pastacode]

Файлы макетов

5. Вставьте следующий код в файл styles.xml:

[pastacode lang=”php” message=”styles.xml” highlight=”” provider=”manual”]

 



 

[/pastacode]

6. Создайте новый файл с именем tool_bar.xml в папке макетов и вставьте следующий код в него:

[pastacode lang=”php” message=”tool_bar.xml ” highlight=”” provider=”manual”]

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:background="@color/ColorPrimary"
    android:elevation="2dp"
    android:theme="@style/Base.ThemeOverlay.AppCompat.Dark"
    xmlns:android="http://schemas.android.com/apk/res/android" />

[/pastacode]

7. Теперь нам нужно добавить Toolbar, SlidingTabLayout и ViewPager в наше Main Activity, поэтому добавьте следующий код в ваш файл activity_main.xml в папке макетов:

[pastacode lang=”php” message=”activity_main.xml” highlight=”” provider=”manual”]

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <include
        android:id="@+id/tool_bar"
        layout="@layout/tool_bar"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        />

    <samples.exoguru.materialtabs.SlidingTabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:elevation="2dp"
        android:background="@color/ColorPrimary"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:layout_weight="1">
     </android.support.v4.view.ViewPager>

</LinearLayout>

[/pastacode]

8. Создадим файлы макетов для вкладок. В моем случае я использую 2 вкладки, и я их называл, tab_1.xml и tab_2.xml:

[pastacode lang=”php” message=”tab_1.xml” highlight=”” provider=”manual”]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

   
     <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Tab 1 says Hello :D"
        android:id="@+id/textView"
        android:textColor="@color/tabsScrollColor"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

[/pastacode]

[pastacode lang=”php” message=”tab_2.xml” highlight=”” provider=”manual”]

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

   
     <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Tab 2 says Hello :D"
        android:id="@+id/textView"
        android:textColor="@color/tabsScrollColor"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

[/pastacode]

Java-файлы

9. Теперь нам нужно сделать два фрагмента для вкладок и макетов, которые мы создали раньше. Нужно создать два java-файла в каталоге Java и добавить следующий код в них, в моем случае я назвал файлы Tab1.java и Tab2.java:

[pastacode lang=”java” message=”Tab1.java” highlight=”” provider=”manual”]

package samples.exoguru.materialtabs;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by Edwin on 15/02/2015.
 */
public class Tab1 extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v =inflater.inflate(R.layout.tab_1,container,false);
        return v;
    }
}

[/pastacode]

[pastacode lang=”java” message=”Tab2.java” highlight=”” provider=”manual”]

package samples.exoguru.materialtabs;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by Edwin on 15/02/2015.
 */
public class Tab2 extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v =inflater.inflate(R.layout.tab_2,container,false);
        return v;
    }
}

[/pastacode]

10. Для обеспечения представления для каждой вкладки, нам нужен ViewPagerAdpater. Создаем новый файл java с именем ViewPagerAdpater.java и добавим в него следующий код:

[pastacode lang=”java” message=”ViewPagerAdpater.java ” highlight=”” provider=”manual”]

package samples.exoguru.materialtabs;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;

/**
 * Created by Edwin on 15/02/2015.
 */
public class ViewPagerAdapter extends FragmentStatePagerAdapter {

    CharSequence Titles[]; // This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
    int NumbOfTabs; // Store the number of tabs, this will also be passed when the ViewPagerAdapter is created


    // Build a Constructor and assign the passed Values to appropriate values in the class
    public ViewPagerAdapter(FragmentManager fm,CharSequence mTitles[], int mNumbOfTabsumb) {
        super(fm);

        this.Titles = mTitles;
        this.NumbOfTabs = mNumbOfTabsumb;

    }

    //This method return the fragment for the every position in the View Pager
    @Override
    public Fragment getItem(int position) {

        if(position == 0) // if the position is 0 we are returning the First tab
        {
            Tab1 tab1 = new Tab1();
            return tab1;
        }
        else             // As we are having 2 tabs if the position is now 0 it must be 1 so we are returning second tab
        {
            Tab2 tab2 = new Tab2();
            return tab2;
        }

    }

    // This method return the titles for the Tabs in the Tab Strip

    @Override
    public CharSequence getPageTitle(int position) {
        return Titles[position];
    }

    // This method return the Number of tabs for the tabs Strip

    @Override
    public int getCount() {
        return NumbOfTabs;
    }
}

[/pastacode]

11. Теперь вам нужно обновить класс populateTabStrip() в файле SlidingTabLayout.Java, просто замените его следующим кодом:

[pastacode lang=”java” message=”SlidingTabLayout.Java” highlight=”” provider=”manual”]

private void populateTabStrip() {
        final PagerAdapter adapter = mViewPager.getAdapter();
        final View.OnClickListener tabClickListener = new TabClickListener();

        for (int i = 0; i < adapter.getCount(); i++) {
            View tabView = null;
            TextView tabTitleView = null;

            if (mTabViewLayoutId != 0) {
                // If there is a custom tab view layout id set, try and inflate it
                tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
                        false);
                tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
            }

            if (tabView == null) {
                tabView = createDefaultTabView(getContext());
            }

            if (tabTitleView == null && TextView.class.isInstance(tabView)) {
                tabTitleView = (TextView) tabView;
            }

            if (mDistributeEvenly) {
                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
                lp.width = 0;
                lp.weight = 1;
            }

            tabTitleView.setText(adapter.getPageTitle(i));
            tabView.setOnClickListener(tabClickListener);
            String desc = mContentDescriptions.get(i, null);
            if (desc != null) {
                tabView.setContentDescription(desc);
            }

            mTabStrip.addView(tabView);
            if (i == mViewPager.getCurrentItem()) {
                tabView.setSelected(true);
            }

            tabTitleView.setTextColor(getResources().getColorStateList(R.color.selector));
            tabTitleView.setTextSize(14);
        }
    }

[/pastacode]

12. И наконец, обновим класс MainActivity.java путем добавления кода ниже:

[pastacode lang=”java” message=”MainActivity.java” highlight=”” provider=”manual”]

package samples.exoguru.materialtabs;

import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;

/**
 * Created by Edwin on 15/02/2015.
 */
public class MainActivity extends ActionBarActivity {

    // Declaring Your View and Variables

    Toolbar toolbar;
    ViewPager pager;
    ViewPagerAdapter adapter;
    SlidingTabLayout tabs;
    CharSequence Titles[]={"Home","Events"};
    int Numboftabs =2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // Creating The Toolbar and setting it as the Toolbar for the activity

        toolbar = (Toolbar) findViewById(R.id.tool_bar);
        setSupportActionBar(toolbar);


        // Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
        adapter =  new ViewPagerAdapter(getSupportFragmentManager(),Titles,Numboftabs);

        // Assigning ViewPager View and setting the adapter
        pager = (ViewPager) findViewById(R.id.pager);
        pager.setAdapter(adapter);

        // Assiging the Sliding Tab Layout View
        tabs = (SlidingTabLayout) findViewById(R.id.tabs);
        tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width

        // Setting Custom Color for the Scroll bar indicator of the Tab View
        tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
            @Override
            public int getIndicatorColor(int position) {
                return getResources().getColor(R.color.tabsScrollColor);
            }
        });

        // Setting the ViewPager For the SlidingTabsLayout
        tabs.setViewPager(pager);



    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

[/pastacode]

Теперь можно запустить приложение и вы должны получить работающие вкладки в стиле Material Design.

Более наглядно весь процесс смотрите в видео:

Ссылка на исходный код проекта.

Перевод источника.

Продвинутый пример создания вкладок в курсе уроков по созданию реального приложения.

 

Коментарі: 5
  1. Марат Ниматуллов

    А так же не понятно. Я нашел эти два файла.
    SlidingTabLayout.java
    SlidingTabStrip.java
    Что я должен с ними сделать?

  2. Марат Ниматуллов

    Не могу скачать исходный код проекта. Помогите.

  3. detsat

    В десятом пункте ошибка “ViewPagerAdpater”

  4. Anton

    Подскажите, как можно разместить на вкладке иконку вместо текста, заранее спасибо

Додати коментар