Material Design
开发很多都要求安卓跟IOS的效果一样,感觉非常不合理 在统一操作系统中统一UI 在14 年谷歌退出material Design;为了解决安卓平台风格不同意的问题,在安卓5.0系统开始,使用这种风格设计, 在 15年推出了design Support这个库;
ToolBar
不适用默认的Actionbar,需要在在资源文件中 values/styles.xml中更改父类parent="Theme.AppCompat.Light.DarkActionBar" 为parent="Theme.AppCompat.Light.NoActionBar"或者
parent ="Theme.AppCompat.NoActionBar"> 二者的区别就是 后者为深色主题,衬托颜色是淡色,前者就相反。
首先在布局文件中声明了一个app 命名空间:xmlns:app="http://schemas.android.com/apk/res-auto",Toolbar代码如下:
<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" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:layout_scrollFlags="scroll|enterAlways|snap" />
上面的theme属性,因为我们的主题选择了淡色的主题,这个时候字体会深色的就是黑色的,所以把这个属性设置为之前的,假如页面中有菜单栏,这个时候弹出的颜色会是深色的,所以加上popuptheme属性。代码两句就搞定:
Toolbar tb = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(tb);
这个时候,如果你在清单文件中的Activity属性中写了 <activity android:name=".MainActivity" android:label="XXXX">属性,如果没有写这个属性,默认使用应用名。
我们的 Toolbar不仅要显示标题还要显示返回按钮等。在res目录新建一个menu文件夹,在里面新建一个toolbar.xml文件,文件内容:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/backup"
android:icon="@drawable/ic_backup"
android:title="Backup"
app:showAsAction="always"/>
<item
android:id="@+id/delete"
android:icon="@drawable/ic_delete"
android:title="Delete"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/settings"
android:icon="@drawable/ic_settings"
android:title="Settings"
app:showAsAction="never"/>
</menu>
并且在代码中增加如下代码:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.backup:
Toast.makeText(this, "You clicked Backup", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "You clicked Delete", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "You clicked Settings", Toast.LENGTH_SHORT).show();
break;
default:
}
return true;
}
滑动菜单
首先是在布局文件中写Drawlayout 这个里面包含2个子项,第一个是主页面显示的,第二个是抽屉边显示的内容;
抽屉的布局需要加一个属性,layout_gravity="left" 指定抽屉在哪边,代码不提示。Material Design库推荐我们设置一个按钮,提示用户有抽屉栏,增加如下代码:
dl = (DrawerLayout) findViewById(R.id.drawlayout);
ActionBar supportActionBar = getSupportActionBar();
if(supportActionBar != null ){
supportActionBar.setDisplayHomeAsUpEnabled(true);
supportActionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
}
....
switch (item.getItemId()) {
case android.R.id.home:
dl.openDrawer(GravityCompat.START);
break;
}
使用NavigationView
使用这个控件来实现左边的菜单选线:
1.添加依赖:
compile 'com.android.support:design:24.2.1'
compile 'de.hdodenhof:circleimageview:2.1.0'
第一个是依赖库,第二个是圆图片处理;
2.增加一个menu文件如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_call"
android:icon="@drawable/nav_call"
android:title="Call" />
<item
android:id="@+id/nav_friends"
android:icon="@drawable/nav_friends"
android:title="Friends" />
<item
android:id="@+id/nav_location"
android:icon="@drawable/nav_location"
android:title="Location" />
<item
android:id="@+id/nav_mail"
android:icon="@drawable/nav_mail"
android:title="Mail" />
<item
android:id="@+id/nav_task"
android:icon="@drawable/nav_task"
android:title="Tasks" />
</group>
</menu>
为了美观,我们还写一个抽屉的头像的布局文件如下:
<?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="180dp"
android:background="?attr/colorPrimary"
android:padding="10dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/icon_image"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerInParent="true"
android:src="@drawable/nav_icon" />
<TextView
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="tonygreendev@gmail.com"
android:textColor="#FFF"
android:textSize="14sp" />
<TextView
android:id="@+id/mail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/username"
android:text="Tony Green"
android:textColor="#FFF"
android:textSize="14sp" />
</RelativeLayout>
下面就是用navigationView这个控件在布局中如下使用:
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_menu" />
下面就添加代码:
nv.setCheckedItem(R.id.nav_call);
nv.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
dl.closeDrawers();
return true;
}
});
默认选择一个,然后点击后就关闭抽屉。
悬浮按钮和可交互提示
FloatingActionButton
实现悬浮按钮! 默认颜色colorAccent ,找到对应ID,设置点击事件就可以了;
<android.support.design.widget.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/floatbutton"
android:layout_gravity="bottom|end"
android:layout_margin="15dp"
android:src="@drawable/ic_done"
android:elevation="18dp" //设置悬浮高度的
/>
Snackbar :
不是Toast的 替代品。与之有不同的应用场景,比如用户删除东西没有交互就删了会很心疼的;
FloatingActionButton fab= (FloatingActionButton) findViewById(R.id.floatbutton);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("", "onClick: "+"sssssssssss" );
Snackbar.make(v,"我是弹唱内容",Snackbar.LENGTH_INDEFINITE).setAction("undo", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"是是是",Toast.LENGTH_LONG).show();
}
}).show();
}
}).show();
这个时候,你会发现弹出的东西吧这个悬浮按钮遮住了。。。
CoordinatorLayout
这个可以说是一个加强的贞布局,可以监听 说有子空间的各种事件,比如刚才的遮住了,当他要弹出来的时候,就把floatingctionBar 往上移动
这个SnackBar并不是他的子空间, 但是还是能接受呢。因为刚才我们传入的第一个参数就是view 就是Snacker 的,所以会有这个效果 如果你试试传入Drawlauoyt
就会被遮挡!
卡片式布局
CardView V 7的 其实也是一个FrameLayout 提供了圆角和阴影效果,看上去有立体效果,用法和普通的差不多,多了两个属性app:cardCornerRadius= "4dp" app:elevition ="5dp" ,添加下面的依赖:
compile 'com.android.support:recyclerview-v7:24.2.1'
compile 'com.android.support:cardview-v7:24.2.1'
compile 'com.github.bumptech.glide:glide:3.7.0'
使用recyclerview来展示列表,定义子项的布局文件如下:
<?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="5dp"
app:cardCornerRadius="4dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="match_parent"
android:layout_height="100dp"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="5dp"
android:textSize="16sp" />
</LinearLayout>
</android.support.v7.widget.CardView>
recycleView的代码如下。但是按照这样,你会发现Toolbar 被挡住了。
RecyclerView 的 写法:
class FirutAdapter extends RecyclerView.Adapter<FirutAdapter.ViewHolder> {
private List<Fruit> mfirutlsit;
private Context mcontext;
@Override
public FirutAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//第三步,从写这个方法
if (mcontext == null) {
mcontext = parent.getContext();
}
View view = LayoutInflater.from(mcontext).inflate(R.layout.rec_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(FirutAdapter.ViewHolder holder, int position) {
// 第四步,在这个方法中处理对应的每一个内容
Fruit fruit = mfirutlsit.get(position);
// holder.imageView.setImageResource(fruit.getImageId());
holder.textView.setText(fruit.getFruitName());
Glide.with(mcontext).load(fruit.getImageId()).into(holder.imageView);
}
@Override
public int getItemCount() {
return mfirutlsit.size();
}
//第一步,把Viewholder这个内部类 改为静态的,然后写他的成员变量。 这个几个都是子项目中的, 然后在这个的构造中,找ID
static class ViewHolder extends RecyclerView.ViewHolder {
CardView cardVie;
ImageView imageView;
TextView textView;
public ViewHolder(View itemView) {
super(itemView);
cardVie = (CardView) itemView;
imageView = (ImageView) itemView.findViewById(R.id.image);
textView = (TextView) itemView.findViewById(R.id.fruitname);
}
}
//第二步,重写整个FriutAdapter的构造,定义一个成员变量,用来接收外部传来的整个数据集合
public FirutAdapter(List<Fruit> fruitList) {
this.mfirutlsit = fruitList;
}
}
MainActivity中:
initFruits();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);
adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
initFruits(){
fruitList.clear();
for (int i = 0; i < 50; i++) {
Random random = new Random();
int index = random.nextInt(fruits.length);
fruitList.add(fruits[index]);
}
}
AppbarLayout
这个相当于是个线性布局,对滑动事件做了封装,,在使用时候。吧toolbar 放在这个里面,然后在recyclerView 中添加一句话
app:layout_behavior="@string/appbar_scrolling_view_behavior"
然后在ToolBar上增加一个属性:
app:layout_scrollFlags="scroll|snap|enterAlways"
scrool表示向下滚时候跟随,,隐藏 向上滚得时候显示, 然后就是显示一般的时候去计算
下拉刷新
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
代码中:
swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
swipeRefresh.setColorSchemeResources(R.color.colorPrimary);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshFruits();
}
});
}
private void refreshFruits() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
initFruits();
adapter.notifyDataSetChanged();
swipeRefresh.setRefreshing(false);
}
});
}
}).start();
}
比起之前的ActionBar ToolBar 是可以随着 RecyclerView移动 但是materail Design 并没说标题就要这样,可以自己定制一个;
可折叠的
CollapsingToolbarLayout 可折叠的
这个不能独立存在,只能依赖AppBarLayout 的子布局
水果详情页面的 布局文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_fruit_detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.aa.mytestdemo.FruitDetail">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="250dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsinglayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="ThemeOverlay.Appcompat.Dark.ActioBar"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="exitUntilCollapsed|scroll">
<ImageView
android:id="@+id/imageDetail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
现在在刚才的RecyclerView 的OncreateViewHolder方法中加入如下代码做点击事件:
final ViewHolder viewHolder = new ViewHolder(view);
viewHolder.cardVie.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int adapterPosition = viewHolder.getAdapterPosition();
Firut firut = mfirutlsit.get(adapterPosition);
Intent intent = new Intent(mcontext,FirutActivity.class);
intent.putExtra("fruit_name",firut.getName());
intent.putExtra("fruit_image_id",firut.getId());
mcontext.startActivity(intent);
}
});
在新建一个Activity 代码中:
package com.yuhan.myapplication;
import android.content.Intent;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
public class FirutActivity extends AppCompatActivity {
public static final String FRUIT_NAME = "fruit_name";
public static final String FRUIT_IMAGE_ID = "fruit_image_id";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_firut);
Intent intent = getIntent();
String fruitName = intent.getStringExtra(FRUIT_NAME);
int fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID, 0);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
ImageView fruitImageView = (ImageView) findViewById(R.id.fruit_image_view);
TextView fruitContentText = (TextView) findViewById(R.id.fruit_content_text);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
collapsingToolbar.setTitle(fruitName);
Glide.with(this).load(fruitImageId).into(fruitImageView);
String fruitContent = generateFruitContent(fruitName);
fruitContentText.setText(fruitContent);
}
private String generateFruitContent(String fruitName) {
StringBuilder fruitContent = new StringBuilder();
for (int i = 0; i < 500; i++) {
fruitContent.append(fruitName);
}
return fruitContent.toString();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
沉浸状态栏
在安卓5.0 钱都不能对系统状态栏 设置。。在除了在Imageview中增加这个属性还需要在他上面的所有增加,
android:fitsSystemWindows="true"
```
但是还是没有效果,现在就需要在 程序的主题中把状态栏的颜色设置为透明的
Android:statusBarColor 指定为@Android:color/transparent 但是这个属性是API 21 也就是安卓5.0才有的
在资源文件中新建一个values-v21文件夹,然后新建一个stely文件
```
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="FriutActivityTheme" parent="AppTheme">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
然后在values文件中增加
<style name="FriutActivityTheme" parent="AppTheme">
</style>
```
然后在清单文件中<activity android:name=".FruitDetail"
android:theme="@style/FriutActivityTheme"></activity>
详细资料参考:https://material.io/guidelines/