Material风格
01 滑动菜单
1 DrawerLayout
??drawerLayout为布局容器.里边有两个子控件,第一个为主屏幕的控件,第二个是滑动后的菜单.第二个控件必须指定layout_gravity
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.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:popupTheme="@style/ThemeOverlay.AppCompat.Light"
/>
</FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:text="this is menu"
android:textSize="30sp"
android:background="#FFF"/>
</androidx.drawerlayout.widget.DrawerLayout>
??滑动时可能会和手机手势发生冲突,这时,可以关闭手势,使用导航.或者开始actionbar的导航按钮.
mainactivity.java
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBar actionBar = getSupportActionBar();
if (actionBar !=null){
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
}
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
mDrawerLayout.openDrawer(GravityCompat.START);
break;
}
return true;
}
}
2 NavigationView
导入依赖
implementation 'com.google.android.material:material:1.1.0'
implementation 'de.hdodenhof:circleimageview:3.0.1'
准备NavigationView中的menu和headerLayout
menu文件nav_menu.xml
??在res目录下新建menu目录,new->Menu resource file
<?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/navCall"
android:icon="@drawable/ic_call"
android:title="Call" />
<item
android:id="@+id/navFriends"
android:icon="@drawable/ic_friend"
android:title="Friends" />
<item
android:id="@+id/navLocation"
android:icon="@drawable/ic_location"
android:title="Location" />
</group>
</menu>
新建nav_header.xml
<?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:padding="10dp"
android:background="?attr/colorPrimary"
>
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/icon_image"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="@drawable/ic_image"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tony"
android:textColor="#FFF"
android:layout_above="@+id/mail"
android:textSize="14sp"/>
<TextView
android:id="@+id/mail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="123456@qq.com"
android:textColor="#FFF"
android:textSize="14sp"/>
</RelativeLayout>
在activity_main中添加
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu"
app:headerLayout="@layout/nav_header"/>
在MainActivity中添加代码
NavigationView navView = (NavigationView) findViewById(R.id.nav_view);
navView.setCheckedItem(R.id.navCall);
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
mDrawerLayout.closeDrawers();
return true;
}
});
02 悬浮按钮和可交互提示
1 悬浮按钮
添加按钮
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src= "@drawable/ic_done"
android:elevation="3dp"
/>
可以设置点击事件
FloatingActionButton fabtn = (FloatingActionButton) findViewById(R.id.fabtn);
fabtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"Fabtn clicked",Toast.LENGTH_SHORT).show();
}
});
2 Snackbar
是Toast的拓展(并不是代替,两者都有自己的适用场景),实现撤销动作
Snackbar.make(v,"Data deleted",Snackbar.LENGTH_SHORT)
.setAction("Undo",new View.OnClickListener(){
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"Data restored",Toast.LENGTH_SHORT).show();
}
})
.show();
3 CoordinatorLayout(加强版framelayout)
??上边的撤销动作出现后会挡住按钮,为了取消这种现象,适用加强版frameLayout,这种布局可以监听所有子控件的各种事件,自动做出合理的响应
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.coordinatorlayout.widget.CoordinatorLayout>
03卡片式布局
1 布局CardView
用到了recyclerView和glide库
导入依赖
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.9.0'
在加强版frameout(非滑动菜单)中使用recyclerView展示图片
在recyclerView中的item使用卡片式布局(有点像悬浮按钮)
recyclerView组件添加(在activity_main中)
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
recyclerView item文件 fruit_item
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
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>
</androidx.cardview.widget.CardView>
recyclerView自定义的adapter
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.MyViewHolder> {
private List<Fruit> data;
private Context context;
public FruitAdapter(List<Fruit> data, Context context) {
this.data = data;
this.context = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = View.inflate(context, R.layout.fruit_item,null);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Fruit fruit = data.get(position);
holder.fruitName.setText(fruit.getName());
Glide.with(context).load(fruit.getImageId()).into(holder.fruitImage);
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder{
private CardView cardView;
private ImageView fruitImage;
TextView fruitName;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
cardView = (CardView) itemView;
fruitImage = (ImageView) cardView.findViewById(R.id.fruit_image);
fruitName = (TextView) cardView.findViewById(R.id.fruit_name);
}
}
}
数据实体
public class Fruit {
private String name;
private int imageId;
}
mainactivity中渲染recyclerView
private Fruit[] fruits = {new Fruit("Apple",R.drawable.fruit_1),new Fruit("Banana",R.drawable.fruit_2)};
private List<Fruit> fruitList = new ArrayList<>();
private FruitAdapter adapter;
initFruits();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
GridLayoutManager layoutManager = new GridLayoutManager(this,2);
recyclerView.setLayoutManager(layoutManager);
adapter = new FruitAdapter(fruitList,this);
recyclerView.setAdapter(adapter);
private void initFruits() {
fruitList.clear();
for (int i = 0; i < 50; i++) {
Random random = new Random();
int index = random.nextInt(fruits.length);
fruitList.add(fruits[index]);
}
}
结果:
2 AppBarLayout(垂直方向上的linearlayout)
??从上图可以看到CoordinatorLayout布局中,toolbar被挡住了.
??CoordinatorLayout就是一个加强版的FrameLayout,那么FrameLayout中的所有控件在不进行明确定位的情况下,默认都会摆放在布局的左上角,从而产生了遮挡的现象。
??解决方法:
在将toolbar放在appbarlayout中
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.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:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways|snap"
/>
</com.google.android.material.appbar.AppBarLayout>
为toolbar和recyclerView添加行为
app:layout_scrollFlags="scroll|enterAlways|snap"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
04 下拉刷新(SwipeRefreshLayout)
??添加依赖
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
recyclerView支持下拉刷新,将recyclerView放入到SwipeRefreshLayout布局中
<androidx.swiperefreshlayout.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"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
swipeRefresh.setColorSchemeResources(R.color.design_default_color_primary);
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();
}
05 可折叠式标题栏(CollapsingToolbarLayout)
??CollapsingToolbarLayout依赖于AppBarLayout ,AppBarLayout依赖于CoordinatorLayout
接下来将于水果详情页使用可折叠式标题栏
效果:
详情页结构如下
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".FruitActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="250dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/fruit_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="35dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/fruit_content_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"/>
</androidx.cardview.widget.CardView>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/ic_comment"
app:layout_anchor="@id/appBar"
app:layout_anchorGravity="bottom|end"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
CoordinatorLayout
??AppBarLayout(可折叠标题栏)
????CollapsingToolbarLayout(可折叠标题栏)
??????ImageView(放图片)
??????ToolBar(普通标题栏)
??NestedScrollView(用于放对水果的描述)
??floatActionButton(评论悬浮按钮)
水果详情页activity.java
public class FruitActivity 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_fruit);
Intent intent = getIntent();
String fruitName = intent.getStringExtra(FRUIT_NAME);
int fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID,0);
CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
Toolbar toolbar = (Toolbar) findViewById(R.id.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(@NonNull MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
设置adpter点击事件
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int positon = getAdapterPosition();
Fruit fruit = data.get(positon);
Intent intent = new Intent(context, FruitActivity.class);
intent.putExtra(FruitActivity.FRUIT_NAME,fruit.getName());
intent.putExtra(FruitActivity.FRUIT_IMAGE_ID,fruit.getImageId());
context.startActivity(intent);
}
});
private OnRecyclerItemClickListener mOnItemClickListener;
public void setmOnItemClickListener(OnRecyclerItemClickListener mOnItemClickListener) {
this.mOnItemClickListener = mOnItemClickListener;
}
public interface OnRecyclerItemClickListener{
void onRecyclerItemClick(int position);
}
1 完善–系统状态栏控件和背景图融合
系统状态栏-电量在的那一行
为要融合的控件和他的父布局添加属性
android:fitsSystemWindows="true"
在res->values->themes.xml添加
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
<style name="FruitActivityTheme" parent="Theme.MyApplication">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
在manifest.xml中的fruitActivity添加如下主题
android:theme="@style/FruitActivityTheme"
效果:
系统栏和图片融合了
|