Android Material Design Library系列教程(二)

尊重劳动成果,转载请注明出处:http://blog.csdn.net/growth58/article/details/48382913
关注新浪微博:@于卫国
邮箱:yuweiguocn@gmail.com

Google在2015 I/O大会上公布了Material Design Support Library,使用它可以创建materail应用在API 19以下突然变得很容易。在这个系列中,我们将使用RSS阅读器应用,我们用于Material系列的基础应用,重写让它完全使用新的Design Support Library
在前面我们做了基本的navigation drawer,在这篇文章中我们将学习怎样实现一个tab bar

ViewPager已经存在有一段时间并且是一个很好使用和理解的组件,因此我很乐意在这里对它做一个完整的说明。让我们看看在ViewPager中使用Fragment的实现。RSS订阅中每个item的内容是基本的HTML,因此我们将使用WebView来控制渲染(请不要讨厌我对这个渲染是多么可怕——它是基本的HTML没有任何CSS呈现进行渲染的。本文的重点是关于内容周围发生的东西而不是怎样渲染内容本身)。

让我们看看fragment布局:

res/layout/fragment_item.xml

<WebView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/web_view"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />

那是相当直接的,也让我们再看一下Fragment 的实现:

ItemFragment.java

public class ItemFragment extends Fragment {
    private static final String KEY_ITEM = "ARG_ITEM";
    public static final String NEWLINE = "\\n";
    public static final String BR = "<br />";
    public static final String HTML_MIME_TYPE = "text/html";

    public static Fragment newInstance(Context context, Item item) {
        Bundle args = new Bundle();
        args.putSerializable(KEY_ITEM, item);
        return Fragment.instantiate(context, ItemFragment.class.getName(), args);
    }

    @Override
    @SuppressLint("SetJavaScriptEnabled")
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Item item = (Item) getArguments().getSerializable(KEY_ITEM);
        View view = inflater.inflate(R.layout.fragment_item, container, false);
        if (item != null) {
            WebView webView = (WebView) view.findViewById(R.id.web_view);
            String html = item.getContent();
            html = html.replaceAll(NEWLINE, BR);
            webView.getSettings().setUseWideViewPort(true);
            webView.getSettings().setLoadWithOverviewMode(true);
            webView.getSettings().setJavaScriptEnabled(true);
            webView.loadData(html, HTML_MIME_TYPE, null);
        }
        return view;
    }
}

还是很直接——进入一个Item,内容被渲染在WebView中。唯一值得注意的是我们替换了换行为了提高渲染。我们也调用了setUseViewPortMode(true)setLoadWithOverviewMote(true)方法在启动时缩小(所以整个内容的宽可以被显示)。这是为移除所有的水平滚动,它将会影响ViewPager容器中的操作。(再次说明,不要讨厌我——ViewPager 是本文的焦点因此我们将修复WebView 渲染以免干扰)。

现在我们已经定义了ViewPager 中的pages ,让我们看看关联到ViewPager上的Adapter

ArticleViewPagerAdapter.java

 public final class ArticleViewPagerAdapter extends FragmentPagerAdapter {
    private final Article article;
    private final Context context;
    private final Resources resources;

    public static ArticleViewPagerAdapter newInstance(FragmentManager fragmentManager, Context context, Article article) {
        Resources resources = context.getResources();
        return new ArticleViewPagerAdapter(fragmentManager, context, resources, article);
    }

    private ArticleViewPagerAdapter(FragmentManager fragmentManager, Context context, Resources resources, Article article) {
        super(fragmentManager);
        this.context = context;
        this.resources = resources;
        this.article = article;
    }

    @Override
    public Fragment getItem(int position) {
        Item item = article.getPartAtPosition(position);
        return ItemFragment.newInstance(context, item);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        FragmentManager manager = ((Fragment) object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment) object);
        trans.commit();
        super.destroyItem(container, position, object);
    }

    @Override
    public int getCount() {
        return article.getPartsCount();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return resources.getString(R.string.part_title, article.getPartNumber(position));
    }
}

这是一个很普通的Adapter 实现。唯一值得注意的是包含了一个getPageTitle()方法的实现(我们用 “Part X”形式生成了一个标题)。使用过v4 support libraryPagerTitleStrip 的人一定熟悉这个,并且新的TabLayout 的实现使用完全相同的机制得到跳转的每个 tab item的文本。

下面我们需要看一下主布局。之前我们定义了一个FrameLayout 包含Toolbar,现在我们需要添加TabLayoutViewPager

res/layout/include_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:id="@+id/main_layout"
  android:layout_width="match_parent"
  android:orientation="vertical"
  android:layout_height="match_parent">

  <android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

  <android.support.design.widget.TabLayout
    android:id="@+id/tab_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:clipToPadding="false"
    android:paddingLeft="@dimen/home_offset"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:tabMode="scrollable" />

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

</LinearLayout>

在这我们已经添加了TabLayout ——这个控件将给我们做好所有工作!我们已经选择了一个操作模式——fixedtabs 是动态的大小,因此TabLayout 是完全适配可用的空间;还有scrollabletabs 是一个固定的大小,如果它们超过可用空间用户可以滚动tabs获取所有。

一般情况下tabs的个数相对少的时候使用fixed模式可以很好的展现,但当tabs的个数太多时使用scrollable模式效果最佳。在这个应用的每篇文章中items 的数量是不定的并且有时可能很大(在示例视频中Dirty Phrasebook包含6部分),因此我选择了scrollable模式。

因为我选择了scrollable 模式,我实际上想让第一个tab文本左边和Toolbar的标题文本对齐,因此我设置了android:paddingLeft来实现这个。当我们滚动tabs时通过设置android:clipToPadding=”false” tabs 将会滚动到左边空白区域。

在布局文件中就还只剩下我们的ViewPager组件。

剩下的工作就是在Activity文件进行关联:

MainActivity.java

public class MainActivity extends AppCompatActivity implements ArticlesConsumer {
    private static final String DATA_FRAGMENT_TAG = DataFragment.class.getCanonicalName();
    private static final int MENU_GROUP = 0;

    private DrawerLayout drawerLayout;
    private NavigationView navigationView;
    private ViewPager viewPager;
    private TabLayout tabLayout;

    private Articles articles;

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

        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        navigationView = (NavigationView) findViewById(R.id.nav_view);
        viewPager = (ViewPager) findViewById(R.id.viewpager);
        tabLayout = (TabLayout) findViewById(R.id.tab_layout);

        setupToolbar();
        setupNavigationView();
        setupDataFragment();
    }
    .
    .
    .
    private void setCurrentArticle(Article article) {
        setTitle(article.getTitle());
        ArticleViewPagerAdapter adapter = ArticleViewPagerAdapter.newInstance(getSupportFragmentManager(), this, article);
        viewPager.setAdapter(adapter);
        if (article.getPartsCount() <= 1) {
            tabLayout.setVisibility(View.GONE);
        } else {
            tabLayout.setVisibility(View.VISIBLE);
        }
        tabLayout.setupWithViewPager(viewPager);
    }
}

当选择一个新的Article时所有的工作在setCurrentArticle()方法中完成。首先我们设置一个新ArticleViewPagerAdapter 实例基于新的Article,然后我们应用到了ViewPager。紧接着做了一个快速检查如果article中只有一部分隐藏TabLayout ,否则显示TabLayout 。最后我们将TabLayout关联到初始了tabsViewPager 上,并且关联了所有的 paging / tab的选择逻辑。这是一次强有力的方法调用!

运行我们可以看到我们已经完全实现了tab bar

这里写图片描述

然而这还有一个很微妙的问题。tab bar支持在已选择的tab的最下面有一个指示条。这个消失的原因是我们在主题中定义了colorAccent值:

res/values/styles.xml

<resources>

  <!-- Base application theme. -->
  <style name="AppTheme" parent="Base.AppTheme" />

  <style name="Base.AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/sa_green</item>
    <item name="colorPrimaryDark">@color/sa_green_dark</item>
    <item name="colorAccent">@color/sa_green</item>
    <item name="colorControlHighlight">@color/sa_green_transparent</item>
  </style>

</resources>

我们声明了同样的颜色值作为colorPrimarycolorPrimary 将会被用作AppBarLayout背景颜色,colorAccent 将被用作指示条的颜色。因为它们的颜色是相同的,所以我们的指示条没有显示。现在我们将colorAccent 设置为白色(但这将会导致一个问题和FloatingActionButton一块使用时,我们遇到时再做处理 ):

res/values/styles.xml

<resources>

  <!-- Base application theme. -->
  <style name="AppTheme" parent="Base.AppTheme" />

  <style name="Base.AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/sa_green</item>
    <item name="colorPrimaryDark">@color/sa_green_dark</item>
    <item name="colorAccent">@android:color/white</item>
    <item name="colorControlHighlight">@color/sa_green_transparent</item>
  </style>

</resources>

现在我们可以看到指示条已经起作用:

这里写图片描述

看起来相当不错,但对于如果我们可以做一个非常material化的东西它还不够好,比如向下滚动Toolbar 消失,还有提供一个快速返回作为用户向上滚动返回。在下一篇文章我们将实现这些。

源代码可以从这下载

请我喝杯咖啡,请使用支付宝扫描下方二维码:

这里写图片描述

原文地址:https://blog.stylingandroid.com/design-library-part-2/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值