prefacio
No hablaré más sobre el uso de RecyclerView. Los próximos artículos hablarán principalmente sobre las funciones prácticas de RecyclerView, incluido el cambio de cuadrícula de lista, el efecto de techo, el efecto de diseño múltiple, etc. El artículo de hoy implementará la lista. La forma de cambiar la red del palacio es la siguiente:
1. Fuente de datos
Los datos provienen de la API diaria de Zhihu, que se solicita mediante la combinación okhttp + retrofit. La solicitud de red no se vuelve a encapsular, simplemente solicita la fuente de datos. Los usuarios que la necesiten pueden realizar modificaciones de encapsulación por sí mismos.
2. Pasos de uso
1. Importar la biblioteca
//万能适配器
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.50'
//卡片布局
implementation 'androidx.cardview:cardview:1.0.0'
//图片加载
implementation 'com.github.bumptech.glide:glide:4.9.0'
//json解析
implementation 'com.alibaba:fastjson:1.2.61'
//标题栏
implementation 'com.github.goweii:ActionBarEx:3.2.2'
// 只引入ActionBarEx
implementation 'com.github.goweii.ActionBarEx:actionbarex:3.2.2'
// 引入ActionBarCommon/Search/Super,依赖于ActionBarEx
implementation 'com.github.goweii.ActionBarEx:actionbarex-common:3.2.2'
2. Obtener datos
Utilice la siguiente URL para realizar solicitudes de datos: Los métodos HTTP utilizados por la API son todos GET
https://news-at.zhihu.com/api/3/news/hot
Ejemplo de respuesta:
{
"recent": [
{
"news_id": 3748552,
"thumbnail": "http://p3.zhimg.com/67/6a/676a8337efec71a100eea6130482091b.jpg",
"title": "长得漂亮能力出众性格单纯的姑娘为什么会没有男朋友?",
"url": "http://daily.zhihu.com/api/2/news/3748552"
}
]
}
Genere la clase de entidad NewsListBean según la instancia e implemente la interfaz de intercambio en serie Serializable
public class NewsListBean implements Serializable {
private String date;
private List<Recent> recent;
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public List<Recent> getRecent() {
return recent;
}
public void setRecent(List<Recent> recent) {
this.recent = recent;
}
public static class Recent implements Serializable {
private String news_id;
private String thumbnail;
private String title;
private String url;
public String getNews_id() {
return news_id;
}
public void setNews_id(String news_id) {
this.news_id = news_id;
}
public String getThumbnail() {
return thumbnail;
}
public void setThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
}
Escriba una clase de interfaz para administrar la API, que se puede colocar en una carpeta separada
public interface ApiUrl {
@GET("/api/4/news/hot")
Call<NewsListBean> getPic();
}
3. Código principal
1 actividad_principal.xml
Aquí, la biblioteca de terceros ActionBarEx se usa para implementar la barra de título inmersiva y la ProgressBar del sistema se usa para implementar el cuadro de carga de solicitudes.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:orientation="vertical">
<per.goweii.actionbarex.ActionBarEx
android:id="@+id/abc_main_return"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#14a4fb"
app:ab_autoImmersion="false"
app:ab_bottomLineColor="#f3f3f3"
app:ab_bottomLineHeight="0dp"
app:ab_statusBarColor="#00000000"
app:ab_statusBarMode="dark"
app:ab_statusBarVisible="true"
app:ab_titleBarHeight="50dp"
app:ab_titleBarLayout="@layout/top" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/zh_lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/abc_main_return" />
<ProgressBar
android:id="@+id/progressbar"
style="@style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone" />
</RelativeLayout>
2 zh_item_layout.xml
Subdiseño de lista, utilizando el diseño de tarjeta CardView
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/zh_card_View"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginTop="10dp"
android:layout_marginRight="@dimen/dp_10"
android:layout_marginBottom="@dimen/dp_10"
app:cardBackgroundColor="#ffffff"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="false">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="120dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent">
<ImageView
android:id="@+id/news_image"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:elevation="2dp"
android:scaleType="fitXY" />
<TextView
android:id="@+id/news_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_toEndOf="@id/news_image"
android:ellipsize="end"
android:maxEms="15"
android:singleLine="true"
android:textColor="@color/black"
android:textSize="20sp" />
</RelativeLayout>
</RelativeLayout>
</androidx.cardview.widget.CardView>
3 zh_grid__item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/zh_card_View"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginTop="10dp"
android:layout_marginRight="@dimen/dp_10"
android:layout_marginBottom="@dimen/dp_10"
app:cardBackgroundColor="#ffffff"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/dp_10">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3">
<ImageView
android:id="@+id/news_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">
<TextView
android:id="@+id/news_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxEms="8"
android:singleLine="true"
android:textColor="@color/black"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
4 Adaptador NewsListAdapter
public class NewsListAdapter extends BaseQuickAdapter<NewsListBean.Recent, BaseViewHolder> {
public NewsListAdapter(int layoutResId, @Nullable List<NewsListBean.Recent> data) {
super(layoutResId, data);
}
@Override
protected void convert(@NonNull BaseViewHolder helper, NewsListBean.Recent item) {
helper.setText(R.id.news_title, item.getTitle());
String img = item.getThumbnail();
ImageView newsImage = helper.getView(R.id.news_image);
Glide.with(mContext).
asBitmap().
load(img).
diskCacheStrategy(DiskCacheStrategy.ALL).
into(newsImage);
helper.addOnClickListener(R.id.zh_card_View);
}
}
5 clase base BaseActivity
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
Window window = getWindow();
// 5.0以上系统状态栏透明
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// 全屏显示,隐藏状态栏和导航栏,拉出状态栏和导航栏显示一会儿后消失。
window.getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
// | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
// | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
// | View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
} else {
// 全屏显示,隐藏状态栏
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
}
}
//预防软键盘挡住输入框
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
//禁止横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
super.onCreate(savedInstanceState);
}
}
6 Código principal de MainActivity
Aquí utilizamos principalmente un valor booleano isGrid para determinar si cambiar de estado para cargar diferentes diseños y el administrador de diseño para lograr el efecto real.
public class MainActivity extends BaseActivity {
private RecyclerView zhLv;
private ProgressBar proBar;
private NewsListAdapter adapter;
private List<NewsListBean.Recent> mList = new ArrayList<>();
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
private ImageView menuBtn;
private LinearLayoutManager layoutManager;
private ImageView btnImg;
private LinearLayout backLayoput;
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE);
}
}
private boolean isGrid = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
verifyStoragePermissions(MainActivity.this);
initView();
initData();
menuBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switchLayout();
}
});
}
private void switchLayout() {
if (isGrid) {
layoutManager = new LinearLayoutManager(this);
adapter = new NewsListAdapter(R.layout.zh_item_layout, mList);
zhLv.setAdapter(adapter);
} else {
layoutManager = new GridLayoutManager(this, 2);
adapter = new NewsListAdapter(R.layout.zh_grid__item_layout, mList);
zhLv.setAdapter(adapter);
}
zhLv.setLayoutManager(layoutManager);
isGrid = !isGrid;
}
private void initView() {
zhLv = findViewById(R.id.zh_lv);
proBar = findViewById(R.id.progressbar);
menuBtn = findViewById(R.id.btn_main_menu);
btnImg = findViewById(R.id.btn_main_menu);
backLayoput = findViewById(R.id.btn_back_layout);
backLayoput.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
layoutManager = new LinearLayoutManager(MainActivity.this);
zhLv.setLayoutManager(layoutManager);
adapter = new NewsListAdapter(R.layout.zh_item_layout, mList);
zhLv.setAdapter(adapter);
}
private void initData() {
proBar.setVisibility(View.VISIBLE);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://news-at.zhihu.com/")
//设置数据解析器
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiUrl apiUrl = retrofit.create(ApiUrl.class);
Call<NewsListBean> call = apiUrl.getPic();
call.enqueue(new Callback<NewsListBean>() {
@Override
public void onResponse(Call<NewsListBean> call, Response<NewsListBean> response) {
List<NewsListBean.Recent> recent = response.body().getRecent();
if (response.body() != null && recent.size() > 0) {
try {
mList.addAll(recent);
adapter.setNewData(mList);
proBar.setVisibility(View.GONE);
} catch (Exception e) {
String message = e.getMessage();
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<NewsListBean> call, Throwable t) {
Log.e("mmm", "errow " + t.getMessage());
}
}
);
}
}
Resumir
Se completa una función pequeña y muy práctica. El próximo artículo continuará implementando el efecto techo de RecyclerView. En el futuro, se agregarán funciones como el almacenamiento en caché local de listas. La demostración se adjunta al final de esta serie de artículos. También te puede gustar y coleccionarlo~
Las colinas verdes no cambiarán, el agua verde fluirá para siempre, nos vemos en los ríos y lagos ~