继续使用上篇文章的项目,拷贝一份并改名为
day21_SwipeRefresh
一、下拉刷新
SwipeRefresh
是用于刷新功能的核心类,将想要实现刷新功能的控件放置到SwipeRefreshLayout
中即可
比如我们要刷新RecycleclerView
:
<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>
需要注意,因为RecyclerView
现在是SwipeRefresh
的子控件,所以app:layout_behavior
也要移到SwipeRefreshLayout
中
差点忘了添加依赖:
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' // 下拉刷新
接着修改主活动,添加刷新逻辑:
private SwipeRefreshLayout swipeRefreshLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
......
swipeRefreshLayout = findViewById(R.id.swipe_refresh);
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
swipeRefreshLayout.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();
swipeRefreshLayout.setRefreshing(false);
}
});
}
}).start();
}
setColorSchemeResources()
设置进度条颜色
setOnRefreshListener()
设置下拉刷新监听器,回调onRefresh()
serRefreshing(false)
表示刷新事件结束,并隐藏刷新进度条
运行:
二、可折叠标题栏
Toolbar
和传统标题栏看起来没啥两样,不过可以响应RecyclerView
的滚动事件进行隐藏和显示。为了实现一个可折叠的标题栏,需要借助CollapsingToolBarLayout
CollapsingToolBarLayout
这个布局作用于Toolbar
,可以让其效果更丰富,但它被限定只能作为AppBarLayout
子布局使用,而AppBarLayout
又必须是CoordinatorLayout
的子布局。
新建一个额外的FruitActivity
来展示水果详情页面,其对应布局:
a. 布局
activity_fruit.xml
的三层套路:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="250dp"
android:id="@+id/appBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/collapsing_toolbar"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
app:contentScrim
:用于指定CollapsingToolbarLayout
在趋于折叠状态及折叠状态之后的背景色
app:layout_scrollFlags
:之前给ToolBar
指定的,现在移到外面:
scroll
表示CollapsingToolbarLayout
会随着水果详情的滚动一起滚动exitUntilCollapsed
表示当CollapsingToolbarLayout
随着滚动完成或折叠之后就保留在界面上,不再移除屏幕
继续在CollapsingToolbarLayout
中定义标题栏的具体内容:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fruit_image_view"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar"
app:layout_collapseMode="pin"/>
app:collapseMode
用于指定当前控件在CollapsingToolbarLayout
折叠过程中的折叠方式:
pin
:位置不变parallax
:折叠会产生一定的错位偏移
接着在和<AppBarLayout>
平级的下面编写内容部分:
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
NestedScrollView
允许用滚动的方式查看屏幕之外的数据,还增加了嵌套响应事件的功能
接着在NestedScrollView
内添加布局:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:id="@+id/fruit_content"/>
</androidx.cardview.widget.CardView>
</LinearLayout>
最后给NestedScrollView
同级之下添加悬浮按钮:
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/like"
app:layout_anchor="@id/appBar"
app:layout_anchorGravity="bottom|end"/>
app:layout_anchor
指定锚点,将锚点设置为AppBarLayout
,这样悬浮按钮就会出现在水果标题栏的区域内
app:layout_anchorGravity
:出现在标题栏的右下角
b. 活动
FruitActivity
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);
Toolbar toolbar = findViewById(R.id.toolbar);
CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
ImageView fruitImageView = findViewById(R.id.fruit_image_view);
TextView fruitContentText = findViewById(R.id.fruit_content);
setSupportActionBar(toolbar);
ActionBar actionBar =getSupportActionBar();
if (actionBar != null){
actionBar.setDisplayHomeAsUpEnabled(true);
}
collapsingToolbarLayout.setTitle(fruitName);
Glide.with(this).load(fruitImageId).into(fruitImageView);
String fruitContent = generateFtuitContent(fruitName);
fruitContentText.setText(fruitContent);
}
private String generateFtuitContent(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);
}
}
actionBar.setDisplayHomeAsUpEnabled(true);
显示标题栏的按钮【默认是返回按钮】
CollapsingToolbarLayout.setTitle()
设置标题
onOptionsItemSelected()
设置了返回按钮的点击事件
c. 适配器
FruitAdapter
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (mContext == null){
mContext = parent.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Intent intent = new Intent(mContext, FruitActivity.class);
intent.putExtra(FruitActivity.FRUIT_NAME, fruit.getName());
intent.putExtra(FruitActivity.FRUIT_IMAGE_ID, fruit.getImageId());
mContext.startActivity(intent);
}
});
return holder;
}
也就是给CardView
注册了一个监听器~
4. 展示
三、融合状态栏
状态栏融合是Android5.0以后才支持的的样式
1、一个属性
要想使背景图和系统状态栏融合,需借助android:fitsSystemWindows
这个属性来实现,将本例中的ImageView
及其所有父布局全部设置这个属性:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="250dp"
android:id="@+id/appBar"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/collapsing_toolbar"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fruit_image_view"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
android:fitsSystemWindows="true"/>
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar"
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="match_parent"
android:orientation="vertical">
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:id="@+id/fruit_content"/>
</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/like"
app:layout_anchor="@id/appBar"
app:layout_anchorGravity="bottom|end"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
2、设置透明
在主题中,将android:statusBarColor
指定成@android:color/transparent
,但只有Android5.0 之后才可以这么设置,所以这里就要实现系统差异处理了。
在res
下新建一个values-v21
目录,在里面建一个values_resource
文件styles.xml
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="FruitActivityTheme" parent="AppTheme">
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>
这里定义了一个FruitActivityTheme
主题,它是专门给FruitActivity
使用的,其parent
主题是Apptheme
,就是说他继承了AppTheme
的所有特性,然后将其状态栏的颜色指定为透明色,而values-v21
是只有Android5.0以上的系统才会读取,因此这么声明没问题
接着为5.0之前的系统单独单的设置values/style.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="FruitActivityTheme" parent="AppTheme" />
</resources>
这里也定义了一个FruitActivityTheme
主题,并且parent
主题也是AppTheme
,但内部是空的,因为5.0之前无法指定状态栏颜色,所以这里啥都不用做
接着在AndroidManifest.xml
中让FruitActivity
使用这个主题:
<activity android:name=".FruitActivity"
android:theme="@style/FruitActivityTheme">
</activity>