您的位置:首页 > 产品设计 > UI/UE

MaterialDesign下的多个UI框架的综合案例详解

2016-09-10 13:03 387 查看
写了几篇关于Design下的UI框架,今天打算结合协调者布局CoordinatorLayout及ToolBar等多个Design下的控件。然后集成成一个小Demo供大家学习。不多说了,大家先看下效果图吧。



首先是布局文件,大体框架是DrawerLayout里面包含一个NavigationView和一个CoordinatorLayout。CoordinatorLayout中则包括AppBarLayout和ViewPager。AppBarLayout里面包含了ToolBar和TabLayout。来看下activity_main.xml:

<android.support.v4.widget.DrawerLayout
android:id="@+id/drawerLayout_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false">

<!-- 内容布局-->
<include layout="@layout/include_content_main"/>

<android.support.design.widget.NavigationView
android:id="@+id/navigationView_main"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header"
app:menu="@menu/menu_navigationview"/>

</android.support.v4.widget.DrawerLayout>
其中NavigationView的介绍,在之前的文章已经介绍了,需要了解的话请到

http://blog.csdn.net/tracy1024/article/details/52202034

内容布局的 include_content_main.xml  就是我所说的CoordinatorLayout:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
android:id="@+id/appBarLayout_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_main"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

<android.support.design.widget.TabLayout
android:id="@+id/tabLayout_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
android:id="@+id/viewPager_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/fab_margin"
android:onClick="clickButton"
android:src="@mipmap/ic_done"/>

</android.support.design.widget.CoordinatorLayout>


接下来我就来介绍下这个布局中的CoordinatorLayout,我习惯称作协调者布局,可以看做一个容器,协调各种子布局的联动。它属于MaterialDesign中比较重要的东东,最常见的情况下是结合CollapsingToolbarLayout一起使用,配合两个空间的不同属性设置形成比较炫酷的动画效果,本例将有涉及到。我接着介绍下上面布局文件中需要注意的地方。CoordinatorLayout内层的AppBarLayout需跟ScollingView并列,我们这里的ScollingView指的是ViewPager。而ViewPager中必须得有

app:layout_behavior="@string/appbar_scrolling_view_behavior"
这个属性。而如果AppBarLayout中的子布局想跟ViewPager联动的话,必须有

app:layout_scrollFlags="scroll|enterAlways"
这个属性与ViewPager的app:layout_behavior相呼应。这个属性代表的意思这个是可以滚动的且一旦向下拉,该属性所修饰的控件就显示。后面我会介绍该属性的其他设置方法。AppBarLayout的话我里面还多放了TabLayout。之前文章也有介绍了,需要了解的话请移步:

http://blog.csdn.net/tracy1024/article/details/52318946

然后这里的ViewPager我们需要用到一个简单的Fragment,由RecyclerView,RecyclerView里的item为CardView组成,RecyclerView和CardView的使用之前文章也有专门介绍过,需要连接的话请移步:

http://blog.csdn.net/tracy1024/article/details/52463503

下面分别是Fragment的布局文件及RecyclerView的布局文件,首先是fragment_dummy.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recyclerView_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />


然后就是item_recyclerview_dummyfragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/card_margin"
android:elevation="5dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="8dp"
app:cardCornerRadius="10dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="horizontal">

<LinearLayout
android:layout_width="120dp"
android:layout_height="120dp"
android:gravity="center"
android:orientation="vertical">

<ImageView
android:layout_width="120dp"
android:layout_height="70dp"
android:background="@mipmap/abc"/>

<Button
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_margin="8dp"
android:background="@drawable/button_bg"
android:text="+关注"
android:textColor="#FFFFFF"/>
</LinearLayout>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:orientation="vertical">

<TextVie
4000
w
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="文章标题"
android:textSize="20sp"
android:textStyle="bold"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="浏览量:40000"
android:textSize="12sp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:ellipsize="end"
android:maxLines="2"
android:text="故事,启迪你的人生;美文,陶冶你的情操,有声朗读,洗礼你的耳朵……"
android:textSize="18sp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="05-20 更新至第78期"/>
</LinearLayout>

</LinearLayout>

</android.support.v7.widget.CardView>


这些如果看了之前我的几篇文章相信都看得明白。这里的数据我为了方便是写死了的。

好了,第一个页面的大体结构就是这样子。我们看下代码怎么用,MainActivity.java:

public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private Context mContext = this;
private DrawerLayout drawerLayout_main;
private NavigationView navigationView_main;
private ViewPager viewPager_main;
private TabLayout tabLayout_main;
private Toolbar toolbar_main;
private List<Fragment> totalList = new ArrayList<Fragment>();

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

initView();

initToolbar();

initTabsAndViewPager();
}

private void initView() {
drawerLayout_main = (DrawerLayout) findViewById(R.id.drawerLayout_main);

//初始化导航试图
navigationView_main = (NavigationView) findViewById(R.id.navigationView_main);
navigationView_main.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
item.setChecked(true);
drawerLayout_main.closeDrawers();
return true;
}
});
}

private void initToolbar() {
//        toolbar_main = (Toolbar) findViewById(R.id.toolbar_main);
//        setSupportActionBar(toolbar_main);
//
//        //重新设置logo前方的图标
//        toolbar_main.setNavigationIcon(R.mipmap.ic_menu);
//        //toolbar_main.setLogo(R.mipmap.ic_launcher);
//        toolbar_main.setTitle("MaterialDesign综合案例");

toolbar_main = (Toolbar) findViewById(R.id.toolbar_main);
setSupportActionBar(toolbar_main);

// 重新设置logo前方的图标
toolbar_main.setNavigationIcon(R.mipmap.ic_menu);
//title默认为APP的名称,也可以重新设置
toolbar_main.setTitle("Design综合案例");
//如果不设置子标题,那么title在垂直居中的位置显示。如果设置则上下各一行显示。可以分别设置文字颜色。
toolbar_main.setSubtitle("Design介绍");//设置子标题
toolbar_main.setTitleTextColor(Color.WHITE);//设置Title的颜色
toolbar_main.setSubtitleTextColor(Color.YELLOW);//设置子标题的颜色
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}

private void initTabsAndViewPager() {
tabLayout_main = (TabLayout) findViewById(R.id.tabLayout_main);
String[] arrTabTitles = getResources().getStringArray(R.array.arrTabTitles);
viewPager_main = (ViewPager) findViewById(R.id.viewPager_main);

for (int i = 0; i < arrTabTitles.length; i++) {
//tabLayout_main.newTab().setIcon(R.mipmap.ic_launcher);
DummyFragment fragment = DummyFragment.getInstance(i + 1);
totalList.add(fragment);
}
PagerAdapter adapter = new MyPagerAdapter(
getSupportFragmentManager(), totalList, arrTabTitles);
viewPager_main.setAdapter(adapter);

tabLayout_main.setupWithViewPager(viewPager_main);//必须设置该属性才能使tab跟ViewPager关联起来
tabLayout_main.setTabsFromPagerAdapter(adapter);//使TabLayout中的tab与Adapter中的fragment对应起来
}

public void clickButton(View view) {
switch (view.getId()) {
//FloatingActionButton的监听事件
case R.id.fab_main:
Snackbar.make(view, "Snackbar comes out", Snackbar.LENGTH_LONG)
.setAction("Action", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, "Toast comes out", Toast.LENGTH_SHORT).show();
}
}).show();
break;
}
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
//ToolBar上面的图标的监听事件,打开NavigationView
case android.R.id.home:
drawerLayout_main.openDrawer(GravityCompat.START);
break;
}
return super.onOptionsItemSelected(item);
}

}
上面需要注意的我添加了注释,上面出现了一个SnackBar,这个我前面并没有说过。这里简单说一下。它也是Design下的控件,跟Toast用法相似,只是它多了个点击监听,如果写成

Snackbar.make(view, "Snackbar comes out", Snackbar.LENGTH_LONG).show();

这样的话则跟普通Toast一样,只是样式不一样。

如果是写成我代码上的那种方式,则可以为弹出的SnackBar中的Action添加点击事件进行具体操作。用法比较简单。上面出现的DummyFragment和MyPagerAdapter这里我也贴下代码。比较简单,DummyFragment:

public class DummyFragment extends Fragment {
private RecyclerView recyclerView_fragment;

public static DummyFragment getInstance(int tabindex) {
DummyFragment fragment = new DummyFragment();
Bundle bundle = new Bundle();
bundle.putInt("tabindex", tabindex);
fragment.setArguments(bundle);
return fragment;
}

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

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView_fragment.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView_fragment.setAdapter(new MainRecyclerAdapter(getActivity()));
}
}
MyPagerAdapter:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> list = null;
private String[] arrTabTitles = null;

public MyPagerAdapter(FragmentManager fm, List<Fragment> list, String[] arrTabTitles) {
super(fm);
this.list = list;
this.arrTabTitles = arrTabTitles;
}

@Override
public Fragment getItem(int position) {
return list.get(position);
}

@Override
public int getCount() {
return list.size();
}

@Override
public CharSequence getPageTitle(int position) {
return arrTabTitles[position];
}
}
然后我们再来看看DummyFragment中RecyclerView中需要的Adapter:MainRecyclerAdapter:

public class MainRecyclerAdapter extends RecyclerView.Adapter<MainRecyclerAdapter.ViewHolder> {

private Context mContext;

public MainRecyclerAdapter(Context mContext) {
this.mContext = mContext;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(mContext).inflate(R.layout.item_recyclerview_dummyfragment, parent, false);
return new ViewHolder(view);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final View view = holder.mView;
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//为每个CardView设置动画过渡然后跳转到详情页
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationZ", 20, 0);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mContext.startActivity(new Intent(mContext, DetailActivity.class));
}
});
animator.start();
}
});
}

@Override
public int getItemCount() {
return 10;
}

public static class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;

public ViewHolder(View view) {
super(view);
mView = view;
}
}
}


到这里结束就是主页面的显示了。接下来就点击MainActivity中的cardView然后跳转的DetailActivity.首先看下它的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="@dimen/detail_backdrop_height"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="#880000ff"
app:expandedTitleMarginEnd="0dp"
app:expandedTitleMarginStart="10dp"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed|exitUntilCollapsed">

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="fitXY"
android:src="@mipmap/ic_banner"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"/>

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_detail"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

</android.support.design.widget.CollapsingToolbarLayout>

</android.support.design.widget.AppBarLayout>

<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView_detail"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_margin"
android:onClick="clickButton"
android:src="@mipmap/ic_discuss"
app:layout_anchor="@id/collapsingToolbarLayout_detail"
app:layout_anchorGravity="bottom|right|end"/>

</android.support.design.widget.CoordinatorLayout>

这个页面的话我是用CoordinatorLayout和CollapsingToolbarLayout一起配合使用。我来解释下每个节点的属性意思:

android:fitsSystemWindows="true"
这句话代表的是设置应用布局时是否考虑系统窗口布局;如果为true,将调整系统窗口布局以适应我自定义的布局。

app:contentScrim="#880000ff"
这个的话我理解为衬托的颜色。就是当我们把页面向下拉的时候,CollapsingToolbarLayout折叠完成时显示的衬托颜色。

app:expandedTitleMarginEnd="0dp"
app:expandedTitleMarginStart="10dp"
这两个属性我是用来展开状态改变标题文字的位置。我们还可以用
app:expandedTitleMargin
app:expandedTitleMarginBottom
这两个来控制。

app:layout_scrollFlags="scroll|enterAlwaysCollapsed|exitUntilCollapsed"
这个的话是用来控制CollapsingToolbarLayout滑动时和设置了behavior属性的控件之间联动的关系。scroll表示是可以滑动的,enterAlwaysCollapsed表示的时向下拉动到顶部时,View才出现。exitUntilCollapsed表示的是当折叠完全(高度已到最小值)时停止折叠。enterAlways表示的是一旦向下拉动,View就露头。snap表示的是滚动到一半后一放手,则全部完成折叠。

ImageViewz中的

app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="0.8"
首先前者没设置为pin,后者则为设置视差。简单来说就是为了ImageView产生视差效果。后者值越大则越不同步。

Toolbar中的

app:layout_collapseMode="pin"
表示在折叠完毕时,停在顶部。

最后是FloatingActionButton的

app:layout_anchor="@id/collapsingToolbarLayout_detail"
app:layout_anchorGravity="bottom|right|end"
这两个属性只有在CoordinatorLayout中才有效,前者表示依附在哪个控件上。后者则表示依附在控件的哪个位置上。

好了。布局文件就是这样子。下面看下DetailActivity的代码:

public class DetailActivity extends AppCompatActivity {
private CollapsingToolbarLayout collapsingToolbarLayout_detail;
private RecyclerView recyclerView_detail;

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

initView();
}

private void initView() {
collapsingToolbarLayout_detail =
(CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout_detail);
collapsingToolbarLayout_detail.setTitle("我的课程");

Toolbar toolbar_detail = (Toolbar) findViewById(R.id.too
b2bd
lbar_detail);
setSupportActionBar(toolbar_detail);
toolbar_detail.setNavigationIcon(R.mipmap.ic_menu);

recyclerView_detail = (RecyclerView) findViewById(R.id.recyclerView_detail);
recyclerView_detail.setLayoutManager(new LinearLayoutManager(this , LinearLayoutManager.VERTICAL , false));
recyclerView_detail.setAdapter(new DetailRecyclerAdapter(this));
}

public void clickButton(View view) {
switch (view.getId()) {
case R.id.fab_detail:
Snackbar.make(view, "您点击了Snackbar!", Snackbar.LENGTH_SHORT).show();
break;
}
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
}
比较简单,我把里面用到的Adapter也贴下代码:

public class DetailRecyclerAdapter extends RecyclerView.Adapter<DetailRecyclerAdapter.ViewHolder> {
private Context mContext;

public DetailRecyclerAdapter(Context mContext) {
this.mContext = mContext;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(mContext).inflate(R.layout.item_cardview_detail, parent, false);
return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

}

@Override
public int getItemCount() {
return 10;
}

public static class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;

public ViewHolder(View view) {
super(view);
mView = view;
}
}
}


到此。完成的例子就讲解到这里了。不好的地方请指出。

共勉!


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息