我是跟着《Android第一行代碼》寫代碼的,想寫個博來加深印象一點
一、添加依賴庫RecyclerView
在app下的build.gradle中的dependencies添加一句:(添加后要sync now)
implementation 'androidx.recyclerview:recyclerview:1.0.0'
二、新建一個新聞類News.java
1 public class News { 2 private String title;//新聞標題 3 private String content;//新聞內容 4 5 public String getTitle() { 6 return title; 7 } 8 9 public void setTitle(String title) { 10 this.title = title; 11 } 12 13 public String getContent() { 14 return content; 15 } 16 17 public void setContent(String content) { 18 this.content = content; 19 } 20 21 22 }
三、新建新聞內容的布局文件news_content_frag.xml
每條新聞內容的布局,頭部顯示新聞標題,正文部分顯示新聞內容,中間用一條細線分隔開,其中,細線使用View實現。
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 6 <LinearLayout 7 android:id="@+id/visibility_layout" 8 android:layout_width="match_parent" 9 android:layout_height="match_parent" 10 android:orientation="vertical" 11 android:visibility="invisible"> 12 13 <TextView 14 android:id="@+id/news_title" 15 android:layout_width="match_parent" 16 android:layout_height="wrap_content" 17 android:gravity="center" 18 android:padding="10dp" 19 android:textSize="20sp"/> 20 <View 21 android:layout_width="match_parent" 22 android:layout_height="1dp" 23 android:background="#000"/> 24 <TextView 25 android:id="@+id/news_content" 26 android:layout_width="match_parent" 27 android:layout_height="0dp" 28 android:layout_weight="1" 29 android:padding="15dp" 30 android:textSize="18sp"/> 31 </LinearLayout> 32 <View 33 android:layout_width="match_parent" 34 android:layout_height="1dp" 35 android:layout_alignParentLeft="true" 36 android:background="#000"/> 37 38 </RelativeLayout>
四、新建NewContentFragment類(雙頁模式)
加載news_content_frag布局和將新聞的標題、內容顯示在界面上。
1 package com.example.fragmentbestpractice; 2 3 import android.os.Bundle; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.TextView; 8 9 import androidx.annotation.NonNull; 10 import androidx.annotation.Nullable; 11 import androidx.appcompat.app.AppCompatActivity; 12 import androidx.fragment.app.Fragment; 13 14 public class NewsContentFragment extends Fragment { 15 private View view; 16 17 @Nullable 18 @Override//加載news_content_frag布局 19 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 20 view=inflater.inflate(R.layout.news_content_frag,container,false); 21 return view; 22 } 23 public void refresh(String newsTitle,String newsContent){ 24 View visibilityLayout=view.findViewById(R.id.visibility_layout);//獲取新聞布局 25 visibilityLayout.setVisibility(View.VISIBLE);//將新聞布局設置成可見 26 TextView newsTitleText=(TextView)view.findViewById(R.id.news_title);//獲取新聞標題的控件 27 TextView newsContentText=(TextView)view.findViewById(R.id.news_content);//獲取新聞內容的控件 28 newsTitleText.setText(newsTitle); //刷新新聞的標題 29 newsContentText.setText(newsContent);//刷新新聞的內容 30 } 31 }
五、單頁模式
若想新聞內容能在單頁模式下也能使用,還需要再創建一個活動NewsContentActivity,並將布局名指定成news_content.xml.
1.news_content.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent"> 6 <fragment 7 android:id="@+id/news_content_fragment" 8 android:name="com.example.fragmentbestpractice.NewsContentFragment" 9 android:layout_width="match_parent" 10 android:layout_height="match_parent"/> 11 </LinearLayout>
這里充分發揮了代碼的復用性,android:name屬性來顯式指明要添加的碎片類名,直接在布局中引入了NewsContentFragment,相當於把news_content_frag布局的內容自動加了進來。
2.NewsContentActivity.java
1 package com.example.fragmentbestpractice; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 5 import android.content.Context; 6 import android.content.Intent; 7 import android.os.Bundle; 8 9 public class NewsContentActivity extends AppCompatActivity { 10 public static void actionStart(Context context,String newsTitle,String newsContent){ 11 Intent intent=new Intent(context,NewsContentActivity.class); 12 intent.putExtra("news_title",newsTitle); 13 intent.putExtra("news_content",newsContent); 14 context.startActivity(intent); 15 } 16 @Override 17 protected void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 setContentView(R.layout.news_content); 20 String newsTitle=getIntent().getStringExtra("news_title");//獲取傳入的新聞標題 21 String newsContent=getIntent().getStringExtra("news_content");//獲取傳入的新聞內容 22 NewsContentFragment newsContentFragment=(NewsContentFragment)getSupportFragmentManager() 23 .findFragmentById(R.id.news_content_fragment); 24 newsContentFragment.refresh(newsTitle,newsContent);//刷新NewsContentFragment界面 25 } 26 }
六、新建一個用於顯示新聞標題列表的布局news_title_frag.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent"> 6 7 <androidx.recyclerview.widget.RecyclerView 8 android:id="@+id/news_title_recycler_view" 9 android:layout_width="match_parent" 10 android:layout_height="match_parent"/> 11 12 </LinearLayout>
RecyclerView子項的布局news_item.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <!--這是標題列表里的每個子項,即每個新聞標題--> 3 <TextView xmlns:android="http://schemas.android.com/apk/res/android" 4 android:id="@+id/news_title" 5 android:layout_width="match_parent" 6 android:layout_height="wrap_content" 7 android:maxLines="1" 8 android:ellipsize="end" 9 android:textSize="18sp" 10 android:paddingLeft="10dp" 11 android:paddingRight="10dp" 12 android:paddingTop="15dp" 13 android:paddingBottom="15dp"> 14 15 </TextView>
七、展示新聞標題列表
NewsTitleFragment.java
1 package com.example.fragmentbestpractice; 2 3 import android.os.Bundle; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.TextView; 8 9 import androidx.annotation.NonNull; 10 import androidx.annotation.Nullable; 11 import androidx.fragment.app.Fragment; 12 import androidx.recyclerview.widget.LinearLayoutManager; 13 import androidx.recyclerview.widget.RecyclerView; 14 15 import java.util.ArrayList; 16 import java.util.List; 17 import java.util.Random; 18 19 /** 20 * 展示新聞列表 21 */ 22 public class NewsTitleFragment extends Fragment { 23 private boolean isTwopane;//判斷是否顯示雙頁 24 25 @Nullable 26 @Override 27 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 28 View view=inflater.inflate(R.layout.news_title_frag,container,false); 34 return view; 35 } 57 @Override 58 public void onActivityCreated(@Nullable Bundle savedInstanceState) { 59 super.onActivityCreated(savedInstanceState); 60 if(getActivity().findViewById(R.id.news_content_layout)!=null){ 61 isTwopane=true;//可以找到news_content_layout布局時,為雙頁模式 62 }else{ 63 isTwopane=false;//找不到news_content_layout布局時,為單頁模式 64 } 65 } 109 } 110 }
修改activity_main.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <!--在單頁模式下,只顯示一個新聞標題碎片--> 3 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 4 android:id="@+id/activity_main" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 > 8 9 <fragment 10 android:id="@+id/news_title_fragment" 11 android:name="com.example.fragmentbestpractice.NewsTitleFragment" 12 android:layout_width="match_parent" 13 android:layout_height="match_parent"/> 14 15 </FrameLayout>
上述代碼表示,在單頁模式下,只會加載一個新聞標題的碎片
新建一個layout-sw600dp文件夾,在該文件夾下新建一個文件,命名為“activity_main.xml”,然后修改里面的代碼
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:orientation="horizontal" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 6 <fragment 7 android:id="@+id/news_title_fragment" 8 android:name="com.example.fragmentbestpractice.NewsTitleFragment" 9 android:layout_width="0dp" 10 android:layout_height="match_parent" 11 android:layout_weight="1"/> 12 <FrameLayout 13 android:id="@+id/news_content_layout" 14 android:layout_width="0dp" 15 android:layout_height="match_parent" 16 android:layout_weight="3"> 17 <fragment 18 android:id="@+id/news_content_fragment" 19 android:name="com.example.fragmentbestpractice.NewsContentFragment" 20 android:layout_width="match_parent" 21 android:layout_height="match_parent"/> 22 23 </FrameLayout> 24 25 26 </LinearLayout>
八、在NewsTitleFragment中通過RecyclerView將新聞列表展示出來,在NewsTitleFragment新建一個內部類NewsAdapter來作為RecyclerView的適配器
NewsTitleFragment.java
package com.example.fragmentbestpractice;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 展示新聞列表
*/
public class NewsTitleFragment extends Fragment {
private boolean isTwopane;//判斷是否顯示雙頁
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.news_title_frag,container,false);
RecyclerView newsTitleRecyclerView=(RecyclerView)view.findViewById(R.id.news_title_recycler_view);
LinearLayoutManager layoutManager=new LinearLayoutManager((getActivity()));
newsTitleRecyclerView.setLayoutManager(layoutManager);
NewsAdapter adapter=new NewsAdapter(getNews());
newsTitleRecyclerView.setAdapter(adapter);
return view;
}
private List<News> getNews() {
List<News> newsList=new ArrayList<>();
for(int i=0;i<=50;i++){
News news=new News();
news.setTitle("This is news title "+i);
news.setContent(getRandomLengthContent("This is news content "+i+"."));
newsList.add(news);
}
return newsList;
}
private String getRandomLengthContent(String content){
Random random=new Random();
int length=random.nextInt(20)+1;
StringBuilder builder=new StringBuilder();
for(int i=0;i<length;i++){
builder.append(content);
}
return builder.toString();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(getActivity().findViewById(R.id.news_content_layout)!=null){
isTwopane=true;//可以找到news_content_layout布局時,為雙頁模式
}else{
isTwopane=false;//找不到news_content_layout布局時,為單頁模式
}
}
class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder>{
private List<News> mNewsList;
class ViewHolder extends RecyclerView.ViewHolder{
TextView newsTitleText;
//構造器傳入一個View參數,View參數就是RecyclerView子項的最外層布局
public ViewHolder(View view){
super(view);
newsTitleText=(TextView)view.findViewById(R.id.news_title);
}
}
//NewsAdapter內部類的構造器,這個方法用於將要展示在界面的數據源傳進來,並賦值給一個全局變量mFruitAdapter
public NewsAdapter(List<News> newsList){
mNewsList=newsList;
}
@NonNull
@Override
//因為NewsAdapter是繼承RecyclerView.Adapeter的,所以必須重寫以下三個方法
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item,parent,false);//加載子項布局
final ViewHolder holder=new ViewHolder(view);//將加載的布局傳入到ViewHolder類構造函數中
view.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {//當用戶點擊每一個新聞標題時,就會顯示新聞內容
News news=mNewsList.get(holder.getAdapterPosition());
if(isTwopane){//如果是雙頁模式,則刷新NewsContentFragment的內容
NewsContentFragment newsContentFragment=(NewsContentFragment)getFragmentManager().findFragmentById(R.id.news_content_fragment);
newsContentFragment.refresh(news.getTitle(),news.getContent());
}else{//如果是單頁模式,直接啟動NewsContentActivity
NewsContentActivity.actionStart(getActivity(),news.getTitle(),news.getContent());
}
}
});
return holder;
}
@Override
//該方法用於對RecyclerView子項的數據進行賦值,會在每個子項被滾動到屏幕內的時候執行
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
News news=mNewsList.get(position);//通過position得到當前項的News實例
holder.newsTitleText.setText(news.getTitle());//在將數據設置到ViewHolder的newsTitleText
}
@Override
//返回數據源長度
public int getItemCount() {
return mNewsList.size();
}
}
}
九、MainActivity.java代碼不用修改,運行項目
結果: