Android學習之在Adapter中調用Fragment


 

•前言

  在學習《第一行代碼》,4.5 小節——一個簡易版的新聞應用的時候🔗

  在為 RecyclerView 創建適配器的時候;

  作者直接在 NewsTitleFragment.java 中新建了一個內部類 NewsAdapter 來作為 RecyclerView 的適配器;

  我就在想,是不是可以將 NewsAdapter 摘出來,作為一個獨立的類來使用;

  本着求知若渴的態度,便產生了這篇博客;

•前行必備

  在簡易版的新聞應用中,為了區分平板和手機,新建了一個 layout-sw600dp 文件夾;

  而本節的重點是如何在 Adapter 中調用 Fragment,所以一切從簡;

  新建一個項目,我命名為 TestFragment,並選擇 Empty Activity;

  這樣 Android Studio 自動生成了 MainActivity.java 和 activity_main.xml 文件;

•漸入佳境

  首先,准備好一個新聞實體類,新建類 News;

News.java

public class News {
    String title;
    String content;

    News(String title,String content){
        this.title = title;
        this.content = content;
    }

    public String getTitle() {
        return title;
    }

    public String getContent() {
        return content;
    }
}

  title 表示新聞標題,content 表示新聞內容;

  接着新建布局文件 right_fragment.xml,用於作為新聞內容的布局;

right_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    android:background="@color/yello">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="30sp"
        android:textColor="@color/black"
        />

    <View
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:background="@color/black"/>

    <TextView
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textSize="20sp"
        android:textColor="@color/gray"
        />

</LinearLayout>

  該代碼的布局和新聞應用中的 news_content_frag.xml 布局大同小異,這里不再贅述;

  在新建一個 RightFragment 類,繼承自 Fragmet;

RightFragment.java

public class RightFragment extends Fragment {

    View view;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.right_fragment,container,false);
        return view;
    }

    public void refresh(String title,String content){
        TextView mTitle = view.findViewById(R.id.title);
        TextView mContent = view.findViewById(R.id.content);

        mTitle.setText(title);
        mContent.setText(content);
    }
}

  該代碼的功能同新聞應用中的 NewsContentFragment 相同;

  接下來創建一個用於顯示新聞列表的布局,新建 left_fragment.xml;

left_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/green"
    android:padding="10dp">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/left_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

  功能同新聞應用中的 news_title_frag;

  新建 item.xml 作為 RecyclerView 子項的布局;

item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/item_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textStyle="bold"
        />

</LinearLayout>

  該代碼中僅放置了一個 TextView 用於展示標題;

  接下來我們就需要一個用於展示新聞列表的地方;

  新建一個 LeftFragment 類作為展示新聞列表的碎片;

LeftFragment.java

public class LeftFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.left_fragment, container, false);
        return view;
    }

}

  在 onCreateView() 方法中加載了 left_fragment 布局;

  接下來就是為 RecyclerView 添加適配器,有兩種方式:

  • 在 LeftFragment.java 中新建一個內部類 NewsAdapter 來作為 RecyclerView 的適配器
  • 將 NewsAdapter 作為一個獨立的類作為 RecyclerView 的適配器

•內部類方式

  修改 LeftFragment.java 中的代碼;

LeftFragment.java

public class LeftFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.left_fragment, container, false);

        RecyclerView rv = view.findViewById(R.id.left_recycler_view);
        LinearLayoutManager manager = new LinearLayoutManager(null);
        rv.setLayoutManager(manager);

        NewsAdapter adapter = new NewsAdapter(getData());
        rv.setAdapter(adapter);

        return view;
    }

    class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder>{

        private List<News> mList;

        class ViewHolder extends RecyclerView.ViewHolder{

            TextView title;
            public ViewHolder(@NonNull View view) {
                super(view);
                title = view.findViewById(R.id.item_text_view);
            }
        }

        public NewsAdapter(List<News> list){
            mList = list;
        }

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
            ViewHolder holder = new ViewHolder(view);

            view.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v) {
                    News news = mList.get(holder.getAdapterPosition());
                    FragmentManager manager = getFragmentManager();
                    RightFragment fragment = (RightFragment) manager.findFragmentById(R.id.right_fragment);
                    fragment.refresh(news.getTitle(),news.getContent());
                }
            });
            return holder;
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            News news = mList.get(position);
            holder.title.setText(news.getTitle());
        }

        @Override
        public int getItemCount() {
            return mList.size();
        }
    }

    private List<News> getData() {
        List<News> list = new ArrayList<>();

        for (int i = 1; i <= 5; i++) {
            list.add(new News("Title" + i, "Content" + i));
        }

        return list;
    }
}

  該方法同新聞應用中的添加適配器的方式相同,在此不再贅述;

運行效果

  

•獨立類方式

  新建一個 NewsAdapter 類,添加如下代碼;

NewsAdapter.java

public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {

    private List<News> mList;

    public class ViewHolder extends RecyclerView.ViewHolder {

        TextView title;

        public ViewHolder(@NonNull View view) {
            super(view);
            title = view.findViewById(R.id.item_text_view);
        }

    }

    public NewsAdapter(List<News> list) {
        mList = list;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
        ViewHolder holder = new ViewHolder(view);

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                News news = mList.get(holder.getAdapterPosition());

                /**
                 * 此處會報錯
                 * 因為 NewsAdapter 並沒有繼承自 Fragment
                 * 所以就無法使用 getFragmentManager() 方法獲取到 FragmentManager
                 */
//                FragmentManager manager = getFragmentManager();

            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        News news = mList.get(position);
        holder.title.setText(news.getTitle());
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

}

  仔細品讀,你會發現,這和內部類中的 NewsAdapter 代碼相差無幾;

  其實不然,在內部類 NewsAdapter 中,由於外部類 LeftFragment 繼承自 Fragment;

  所以,在   view.setOnClickListener() 的  onClick()  中就可以使用  FragmentManager manager = getFragmentManager(); ;

  但是,將 NewsAdapter 摘出來作為一個獨立的類,其並沒有繼承自 Fragment,所以,不能使用  getFragmentManager() 方法;

  那我們是不是可以這樣做,在點擊 item 的時候,通過  onClick()  方法中的  News news = mList.get(holder.getAdapterPosition()); 方法,將被點擊項的 title 和 content 傳遞到 LeftFragment 中;

  然后,在 LeftFragment 中進行 Fragment 的一系列操作?

  你別說,還真行,這就需要通過 Java 的回調機制來實現;

  鄙人不才,之前學了一點回調的知識,特此獻上🔗

  首先,我們在 NewsAdapter.java 中添加一個回調接口 CallBack,並在 NewsAdapter.java 中聲明一個 CallBack;

public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {

    private List<News> mList;
    private CallBack callBack;//聲明一個 CallBack

    public class ViewHolder extends RecyclerView.ViewHolder {...}

    public NewsAdapter(List<News> list) {...}


    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {...}

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {...}

    @Override
    public int getItemCount() {...}

}
//添加一個回調接口 CallBack
interface CallBack{
    void onClick(News news);
}

  接下來就是定義 setCallBack() 方法了;

  修改 NewsAdapter.java 中的代碼;

public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {

    private List<News> mList;
    private CallBack callBack;//聲明一個 CallBack

    public class ViewHolder extends RecyclerView.ViewHolder {...}

    public NewsAdapter(List<News> list) {...}

    //定義 setCallBack() 方法
    public void setCallBack(CallBack callBack){
        this.callBack = callBack;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {...}

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {...}

    @Override
    public int getItemCount() {...}

}
//添加一個回調接口 CallBack
interface CallBack{
    void onClick(News news);
}

  然后,就是通過  onClick() 方法傳遞被點擊項 title 和 content 了;

  修改 view.setOnClickListener() 中的  onClick() 方法;

@NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        
        ...

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                News news = mList.get(holder.getAdapterPosition());

                /**
                 * 此處會報錯
                 * 因為 NewsAdapter 並沒有繼承自 Fragment
                 * 所以就無法使用 getFragmentManager() 方法獲取到 FragmentManager
                 */
//                FragmentManager manager = getFragmentManager();

                /**
                 * 把 news.getTitle() 和 news.getContent() 傳遞到 LeftFragment 中
                 * 這就需要使用回調方法
                 */
                callBack.onClick(news);
            }
        });
        return holder;
    }

  通過 callBack.onClick(news); 方法傳遞 title 和 content 信息;

  接下來,就是在 LeftFragment.java 中通過回調接收 news 了;

  修改 LeftFragment.java 中的代碼;

public class LeftFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.left_fragment, container, false);

        RecyclerView rv = view.findViewById(R.id.left_recycler_view);
        LinearLayoutManager manager = new LinearLayoutManager(null);
        rv.setLayoutManager(manager);

        NewsAdapter adapter = new NewsAdapter(getData());
        
        CallBack callBack = new CallBack() {
            @Override
            public void onClick(News news) {
                FragmentManager manager1 = getFragmentManager();
                RightFragment fragment = (RightFragment) manager1.findFragmentById(R.id.right_fragment);
                fragment.refresh(news.getTitle(),news.getContent());
            }
        };
        adapter.setCallBack(callBack);
        
        rv.setAdapter(adapter);

        return view;
    }


    private List<News> getData() {
        List<News> list = new ArrayList<>();

        for (int i = 1; i <= 5; i++) {
            list.add(new News("Title" + i, "Content" + i));
        }

        return list;
    }
}

  到這,就大功告成了;

  運行一下,你會發現,成功實現內部類的實現效果;

•聲明

  參考資料:

  【adapter調用fragment中的方法

  【在適配器Adapter中回調他的點擊事件到activity或者fragment當中

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM