RecyclerView列表中。ItemTouchHelper以将拖放功能添加到您的应用程序。项目地址:https://github.com/google-developer-training/android-fundamentals-starter-apps/tree/master/MaterialMe-Starter
打开并运行MaterialMe项目

直接构建错误了…
有些年代了这项目,
复刻一个
创建新项目

主布局activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_margin="16dp"
android:onClick="resetSports"
android:src="@drawable/ic_reset"
android:tint="@android:color/white" />
RelativeLayout>
list_item.xml
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/sportsImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<TextView
android:id="@+id/title"
style="@style/TextAppearance.AppCompat.Headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/sportsImage"
android:padding="8dp"
android:text="@string/title_placeholder"
android:theme="@style/ThemeOverlay.AppCompat.Dark" />
<TextView
android:id="@+id/newsTitle"
style="@style/TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sportsImage"
android:padding="8dp"
android:text="@string/news_placeholder"
android:textColor="?android:textColorSecondary" />
<TextView
android:id="@+id/subTitle"
style="@style/TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/newsTitle"
android:text="@string/sports_info_placeholder" />
RelativeLayout>
androidx.cardview.widget.CardView>
新建一个Activity,DetailActivity.java

package com.dingjiaxiong.materialme;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
public class DetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
TextView sportTitle = findViewById(R.id.titleDetail);
ImageView sportImage = findViewById(R.id.sportsImageDetail);
sportTitle.setText(getIntent().getStringExtra("title"));
Glide.with(this).load(getIntent().getIntExtra("image_resource",0))
.into(sportImage);
}
}
布局文件
activity_detail.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".DetailActivity">
<ImageView
android:id="@+id/sportsImageDetail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<TextView
android:id="@+id/titleDetail"
style="@style/TextAppearance.AppCompat.Headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/sportsImageDetail"
android:padding="16dp"
android:text="@string/title_placeholder"
android:theme="@style/ThemeOverlay.AppCompat.Dark" />
<TextView
android:id="@+id/newsTitleDetail"
style="@style/TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sportsImageDetail"
android:padding="16dp"
android:text="@string/news_placeholder"
android:textColor="?android:textColorSecondary" />
<TextView
android:id="@+id/subTitleDetail"
style="@style/TextAppearance.AppCompat.Subhead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/newsTitleDetail"
android:padding="16dp"
android:text="@string/subtitle_detail_text" />
RelativeLayout>
ScrollView>
新建Sport.java
package com.dingjiaxiong.materialme;
public class Sport {
private String title;
private String info;
private final int imageResource;
public Sport(String title, String info, int imageResource) {
this.title = title;
this.info = info;
this.imageResource = imageResource;
}
public String getTitle() {
return title;
}
public String getInfo() {
return info;
}
public int getImageResource() {
return imageResource;
}
}
新建适配器SportsAdapter.java
package com.dingjiaxiong.materialme;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import java.util.ArrayList;
public class SportsAdapter extends RecyclerView.Adapter<SportsAdapter.ViewHolder> {
private ArrayList<Sport> mSportData;
private Context mContext;
public SportsAdapter(ArrayList<Sport> mSportData, Context mContext) {
this.mSportData = mSportData;
this.mContext = mContext;
}
@NonNull
@Override
public SportsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false));
}
@Override
public void onBindViewHolder(@NonNull SportsAdapter.ViewHolder holder, int position) {
Sport currentSport = mSportData.get(position);
holder.bindTo(currentSport);
}
@Override
public int getItemCount() {
return mSportData.size();
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mTitleText;
private TextView mInfoText;
private ImageView mSportImage;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTitleText = itemView.findViewById(R.id.title);
mInfoText = itemView.findViewById(R.id.subTitle);
mSportImage = itemView.findViewById(R.id.sportsImage);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Sport currentSport = mSportData.get(getAdapterPosition());
Intent detailIntent = new Intent(mContext, DetailActivity.class);
detailIntent.putExtra("title", currentSport.getTitle());
detailIntent.putExtra("image_resource", currentSport.getImageResource());
mContext.startActivity(detailIntent);
}
public void bindTo(Sport currentSport) {
mTitleText.setText(currentSport.getTitle());
mInfoText.setText(currentSport.getInfo());
Glide.with(mContext).load(currentSport.getImageResource()).into(mSportImage);
}
}
}
这里用到了Glide,需要手动导入
implementation 'com.github.bumptech.glide:glide:4.13.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
最后MainActivity.java
package com.dingjiaxiong.materialme;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.view.View;
import java.util.ArrayList;
import java.util.Collections;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private ArrayList<Sport> mSportsData;
private SportsAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = findViewById(R.id.recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mSportsData = new ArrayList<>();
mAdapter = new SportsAdapter(mSportsData, this);
mRecyclerView.setAdapter(mAdapter);
//获取数据
initializeData();
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT |
ItemTouchHelper.DOWN | ItemTouchHelper.UP,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
Collections.swap(mSportsData, from, to);
mAdapter.notifyItemMoved(from, to);
return true;
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
mSportsData.remove(viewHolder.getAdapterPosition());
mAdapter.notifyItemRemoved(viewHolder.getAdapterPosition());
}
});
helper.attachToRecyclerView(mRecyclerView);
}
private void initializeData() {
String[] sportsList = getResources()
.getStringArray(R.array.sports_titles);
String[] sportsInfo = getResources()
.getStringArray(R.array.sports_info);
TypedArray sportsImageResources = getResources()
.obtainTypedArray(R.array.sports_images);
mSportsData.clear();
for (int i = 0; i < sportsList.length ; i++){
mSportsData.add(new Sport(sportsList[i],sportsInfo[i],sportsImageResources.getResourceId(i,0)));
}
sportsImageResources.recycle();
mAdapter.notifyDataSetChanged();
}
public void resetSports(View view) {
initializeData();
}
}
运行一把
官方效果图


复刻成功
探索应用程序
Sport.java
此类表示RecyclerView. 现在,它包含一个用于运动标题的字段和一个用于该运动的一些信息的字段。
SportsAdapter.java
这是RecyclerView. 它使用一个ArrayListSport 对象作为其数据,并用该数据填充每一行。
MainActivity.java
MainActivity初始化 RecyclerView 和适配器,并从资源文件创建数据。
strings.xml
此资源文件包含应用程序的所有数据,包括每项运动的标题和信息。
list_item.xml
此布局文件定义RecyclerView. 它由三个TextView元素组成,一个用于每条数据(每项运动的标题和信息),另一个用作标签。
其实到这里,笔者复刻出来后,本此课要讲的东西就结束了,走下流程吧。
又是新知识
【卡片视图】不错
实现滑动关闭
Android SDK 包含一个名为的类 ItemTouchHelper,用于定义RecyclerView当用户执行各种触摸操作(例如滑动或拖放)时列表项会发生什么。
实现拖放
实现DetailActivity详情页布局
实现详情视图和点击事件的监听
CardView是一个很好的布局,用于呈现具有混合媒体(例如图像和文本)的信息。CardView是 Android 支持库中的一个 UI 组件。CardView不仅仅是为文本子View元素设计的。ImageView内存中会占用大量内存,因为图像是以全分辨率加载的。为了有效地将图像加载到您的应用程序中,请使用图像加载库,例如 Glide。ItemTouchHelper,可帮助您的应用获取有关 UI 中的点击、滑动和拖放事件的信息。FloatingActionButton(FAB) 让用户关注特定操作并在您的 UI 中“浮动”。CardView和 FAB 小部件。