"La première ligne de code" Chapitre 4 : Meilleures pratiques pour la fragmentation

1. Utilisation simple des fragments

Ajoutez deux fragments à une activité et laissez les deux fragments diviser l'espace de l'activité de manière égale.

Étape 1 : créez d'abord left_fragment.xml dans la mise en page :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="button"/>

</LinearLayout>

et fragment_droit :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="#00ff00"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:textSize="20sp"
        android:text="文本"></TextView>

</LinearLayout>

Étape 2 : Créer les classes leftFragment.class et rightFragment.class

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;
    }
}

et:

public class RightFragment 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;
    }
}

Étape 3 : Modifier le fichier mainActivity.xml et l'importer par son nom

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        />
    <fragment
        android:id="@+id/right_fragment"
        android:name="com.example.fragmenttest.RightFragment"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        />
</LinearLayout>

Ce qu'il réalise :
insérez la description de l'image ici
Cela ne semble pas très différent des composants du frontal.

Deuxièmement, ajoutez dynamiquement des fragments

1. La première étape : Créez another_right_fragment.xml de l'instance de fragment à ajouter :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="#ffff00"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="另一个碎片"
        android:textSize="20sp"/>

</LinearLayout>

2. La deuxième étape : modifier mainActivity.xml

Il s'agit d'imbriquer la disposition FrameLayout sous la disposition LinearLayout :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/left_fragment"
        android:name="com.example.fragmenttest.LeftFragment"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        />
    <FrameLayout
        android:id="@+id/right_layout"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        />
</LinearLayout>

3. Modifier dans l'activité principale de mainActivity.class

Autrement dit, par défaut, un fragment est rendu en premier dans le fragment de droite, puis les fragments du conteneur FrameLayout sont commutés en cliquant sur le bouton.

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //右侧活动初始展示的碎片
        replaceFragment(new RightFragment());
        //点击左侧的按钮
        Button button =(Button) findViewById(R.id.button);
        button.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
    
    
        switch(view.getId()){
    
    
            case R.id.button:
                replaceFragment(new AnotherRightFragment());
                break;
            default:
                break;
        }
    }

    private void replaceFragment(Fragment fragment) {
    
    
        //1,创建新的碎片实例new AnotherRightFragment()
        //2,获取FragmentManager
        FragmentManager fragmentManager =getSupportFragmentManager();
        //3,通过beginTransaction()开启一个事务
        FragmentTransaction transaction=fragmentManager.beginTransaction();
        //4,向容器内添加事务,(容器的id,待添加的碎片实例)
        transaction.replace(R.id.right_layout,fragment);
        //提交事务才能完成
        transaction.commit();
    }
}

4. Simulez la pile de retour en fragments

L'effet que je veux obtenir est que lorsque le bouton de retour est cliqué, le fragment peut revenir au lieu de revenir directement à la pile active précédente.
Modifiez le fichier MainActivity.class :

    private void replaceFragment(Fragment fragment) {
    
    
        //1,创建新的碎片实例new AnotherRightFragment()
        //2,获取FragmentManager
        FragmentManager fragmentManager =getSupportFragmentManager();
        //3,通过beginTransaction()开启一个事务
        FragmentTransaction transaction=fragmentManager.beginTransaction();
        //4,向容器内添加事务,(容器的id,待添加的碎片实例)
        transaction.replace(R.id.right_layout,fragment);
        //将事务添加到返回栈中,一般传入null就行,这样碎片中的活动就会和已经加入返回栈中一样
        transaction.addToBackStack(null);
        //提交事务才能完成
        transaction.commit();
    }

De cette façon, c'est comme si les activités du fragment se trouvaient toutes sur la pile arrière.

5. Communication entre fragments et activités

Bien que les fragments soient imbriqués dans les activités, ils ne sont en fait pas étroitement liés. Vous pouvez voir que les fragments et les activités existent dans une classe distincte et qu'il n'existe aucun moyen évident de communiquer directement entre eux.
Ensuite, si je veux appeler la méthode dans le fragment de l'activité maintenant, ou appeler la méthode de l'activité dans le fragment. Comment doit-il être atteint?
FragmentManager fournit une méthode similaire à findViewById(), qui est spécialement utilisée pour obtenir des instances de fragment à partir de fichiers de mise en page. Le code est le suivant :

RightFragment rightFragment = (RightFragment) getFragmentManager().findFragmentById(R.id.right fragment);

Appelez la méthode findFragmentById() de FragmentManager, vous pouvez obtenir l'instance du fragment correspondant dans l'activité, puis vous pouvez facilement appeler la méthode dans le fragment.
Comment obtenir l'instance de l'activité dans le fragment ?

MainActivity activity = (MainActivity) getActivity();

Troisièmement, le cycle de vie des fragments

insérez la description de l'image ici

Quatrièmement, la technique de chargement dynamique de la mise en page

1. Utilisez des qualificatifs

L'utilisation de qualificatifs permet au programme de déterminer l'environnement dans lequel le programme en cours s'exécute, utilisant ainsi le mode page simple ou le mode double page.
insérez la description de l'image ici
Par exemple : Mais lorsque notre téléphone mobile doit afficher une page et que la tablette à écran large doit afficher deux vignettes de page, cela peut être :
écrivez d'abord la mise en page normale du mode page unique dans layout/activity_main.xml.
Créez ensuite un nouveau dossier sous res: layout-large et créez un nouveau fichier activity_main.xml avec le même nom. Une disposition à double écran pour une tablette d'écriture.
Une fois le programme exécuté, il jugera l'environnement, lira le code en format large lorsqu'il s'agit d'une tablette, sinon lira le code en format.

2. Utilisez le qualificateur min-width

Si nous voulons contrôler exactement les requêtes des médias.
Créez un nouveau dossier layout-sw660dp sous res, puis créez un nouveau fichier activity_main.xml avec le même nom pour écrire la mise en page. De cette façon, lorsque le programme s'exécute sur un appareil d'une largeur supérieure à 600dp, le layout layout-sw600dp/activity_main sera chargé, sinon le layout layout/activity_main par défaut sera chargé.

Cinq, la meilleure application de fragments

Si, comme ci-dessus, un ensemble de codes est écrit pour chaque appareil, la charge de travail sera énorme et la maintenance ultérieure sera difficile.

Étape 1 : introduire recycleview dans build.gradle

dependencies {
    
    
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
}

Étape 2 : préparer une classe d'entités d'actualités

public class News {
    
    
    public String title;
    public String content;
    public String getTitle(){
    
    
        return title;
    }
    public void setTitle(String title) {
    
    
        this.title = title;
    }
    public String getContent() {
    
    
        return content;
    }
    public void setContent(String content) {
    
    
        this.content = content;
    }
}

Étape 3 : Créer un nouveau fichier de mise en page news_content_frag.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/visibility_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="invisible">
        <TextView
            android:id="@+id/news_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="10dp"
            android:textSize="20sp"/>
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#000"/>
        <TextView
            android:id="@+id/news_content"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:padding="15dp"
            android:textSize="18sp"/>
    </LinearLayout>
    <View
        android:layout_width="1dp"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:background="#000"/>

</RelativeLayout>

La mise en page du contenu de l'actualité est principalement divisée en deux parties, la tête affiche le titre de l'actualité et le corps affiche le contenu de l'actualité, séparés par une fine ligne au milieu.

Étape 4 : Créez une nouvelle classe NewsContentFragment :

package com.example.fragmenttest;


import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.fragment.app.Fragment;

public class NewsContentFragment extends Fragment {
    
    
    private View view;

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    
    
        //加载新闻布局
        view = inflater.inflate(R.layout.news_content_frag, container, false);
        return view;
    }

    /**
     * 将新闻标题和新闻内容显示在界面上  用来刷新新闻详情
     */
    public void refresh(String newsTitle, String newsContent) {
    
    
        View visibilityLayout = view.findViewById(R.id.visibility_layout);
        visibilityLayout.setVisibility(View.VISIBLE);//把visibilityLayout设置成可见
        TextView newsTitleText = (TextView) view.findViewById(R.id.news_title);//获取新闻标题控件
        TextView newsContentText = (TextView) view.findViewById(R.id.news_content);//获取新闻正文控件
        newsTitleText.setText(newsTitle);//刷新新闻标题
        newsContentText.setText(newsContent);//刷新新闻内容
    }
}

Tout d'abord, la mise en page de frag de contenu d'actualités que nous venons de créer est chargée dans la méthode onCreateView(), ce qui n'a rien à expliquer. Ensuite, une méthode refresh() est fournie, qui est utilisée pour afficher le titre et le contenu de l'actualité sur l'interface. On peut voir que les contrôles du titre et du contenu de l'actualité sont respectivement obtenus via la méthode findViewBvId), puis les paramètres passés par la méthode sont définis.
De cette manière, le fichier de classe de fragment et la mise en page xml du contenu de l'actualité sont créés.
Mais ils sont tous utilisés en mode double page. Si vous souhaitez l'utiliser en mode page unique. Une autre activité doit être créée.

Étape 5 : Créer un nouveau fichier NewsContentActivity

Le fichier news_content.xml correspondant sera automatiquement créé et modifié pour :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <fragment
        android:id="@+id/news_content_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="com.example.fragmenttest.NewsContentFragment"/>

</LinearLayout>

La classe NewsContentFragment créée ci-dessus est directement introduite ici, ce qui équivaut à introduire le fichier de mise en page news_content_frag.xml.
Modifiez ensuite le code dans newsContentActivity :

public class NewsContentActivity extends AppCompatActivity {
    
    
    /**
     * 构建Intent,传递所需数据
     */
    public static void actionStart(Context context, String newsTitle, String newsContent){
    
    
        Intent intent  = new Intent(context,NewsContentActivity.class);
        intent.putExtra("news_title",newsTitle);
        intent.putExtra("news_content",newsContent);
        context.startActivity(intent);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_content);
        //获取传入的新闻标题、新闻内容
        String newsTitle = getIntent().getStringExtra("news_title");
        String newsContent = getIntent().getStringExtra("news_content");
        //获取NewsContentFragment 实例
        NewsContentFragment newsContentFragment = (NewsContentFragment) getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);
        //刷新NewsContentFragment   显示数据
        newsContentFragment.refresh(newsTitle,newsContent);
    }
}

Dans la méthode onCreate(), obtenez le titre et le contenu des actualités entrantes via Intent

Appelez ensuite la méthode findFragmentById() de FragmentManager pour obtenir une instance de NewsContentFragment

Appelez ensuite sa méthode refresh() et transmettez le titre et le contenu de l'actualité pour afficher les données

Étape 6 : Créez la mise en page news_title_frag.xm de la liste des actualités

Ensuite, nous devons créer la mise en page news_title_frag.xml qui affiche la liste des actualités, comme suit :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <!--新闻列表-->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/news_title_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</LinearLayout>
 

Étape 7 : Créer un nouveau news_item.xml comme mise en page des sous-éléments RecyclerView ci-dessus

<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/news_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:singleLine="true"
    android:ellipsize="end"
    android:textSize="18sp"
    android:padding="10dp"/>

La mise en page du sous-élément est uniquement une
liste de nouvelles TextView et une mise en page de sous-élément est créée, puis un emplacement pour afficher la liste de nouvelles est nécessaire. Ici, un nouveau
NewsTitleFragment est créé en tant que fragment pour afficher la liste de nouvelles :

/**
 * 新闻列表fragment
 */
 
public class NewsTitleFragment extends Fragment{
    
    
 
    private boolean isTowPane;
 
    @Override
    public View onCreateView(LayoutInflater inflater,  ViewGroup container,  Bundle savedInstanceState) {
    
    
        View view = inflater.inflate(R.layout.news_content_frag, container, false);
        return view;
    }
 
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    
    
        super.onActivityCreated(savedInstanceState);
        if (getActivity().findViewById(R.id.news_content_layout)!= null){
    
    
            // 可以找到 news_content_layout 布局时,为双页模式
            isTowPane = true;
        }else {
    
    
            // 找不到 news_content_layout 布局时,为单页模式
            isTowPane = false;
        }
    }
}

Afin de réaliser la méthode onActivityCreated() mentionnée ci-dessus pour déterminer si le mode double page ou simple page actuel
est le suivant, créez une classe interne NewsAdapter dans NewsTitleFragemt en tant qu'adaptateur pour RecyclerView
comme suit :

public class NewsTitleFragment extends Fragment{
    
    
 
    private boolean isTowPane;
 
    . . .
    
    /**
     * RecyclerViews适配器
     * */
    class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
    
    
 
        private List<News> mNewsList;
 
        class ViewHolder extends RecyclerView.ViewHolder {
    
    
 
            TextView newsTitleText;
 
            public ViewHolder(View view) {
    
    
                super(view);
                newsTitleText = (TextView) view.findViewById(R.id.news_title);//新闻标题
            }
 
        }
 
        public NewsAdapter(List<News> newsList) {
    
    
            mNewsList = newsList;
        }
 
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    
    
            //加载布局
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
            //每个Item的点击事件
            final ViewHolder holder = new ViewHolder(view);
            view.setOnClickListener(new View.OnClickListener() {
    
    
                @Override
                public void onClick(View v) {
    
    
                    News news = mNewsList.get(holder.getAdapterPosition());
                    //如果是双页模式,则刷新NewsContentActivity中的数据
                    if (isTwoPane) {
    
    
                        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
        public void onBindViewHolder(ViewHolder holder, int position) {
    
    
            News news = mNewsList.get(position);
            holder.newsTitleText.setText(news.getTitle());
        }
        @Override
        public int getItemCount() {
    
    
            return mNewsList.size();
        }
    
    }

Il convient de noter que l'adaptateur est écrit ici comme une classe interne pour accéder directement aux variables de NewsTitleFragment.
Par exemple : isTowPane
a maintenant la dernière étape du travail de finition, qui consiste à remplir le RecyclerView avec des données
. Modifiez le code dans NewsTitleFragment comme suit :

public class NewsTitleFragment extends Fragment{
    
    
 
    . . .
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    
    
        View view = inflater.inflate(R.layout.news_title_frag, container, false);
        
        //RecyclerView实例
        RecyclerView newsTitleRecyclerView = (RecyclerView) view.findViewById(R.id.news_title_recycler_view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        newsTitleRecyclerView.setLayoutManager(layoutManager);//指定布局为线性布局
        NewsAdapter adapter = new NewsAdapter(getNews());//把模拟新闻数据传入到NewsAdapter构造函数中
        newsTitleRecyclerView.setAdapter(adapter);//完成适配器设置
        return view;
    }
 
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
    
    
        super.onActivityCreated(savedInstanceState);
        if (getActivity().findViewById(R.id.news_content_layout) != null) {
    
    
            // 可以找到news_content_layout布局时,为双页模式
            isTwoPane = true;
        } else {
    
    
            // 找不到news_content_layout布局时,为单页模式
            isTwoPane = false;
        }
    }
 
    /**
     * 初始化50条模拟新闻数据
     * @return
     */
     private List<News> getNews() {
    
    
        //创建集合
        List<News> newsList = new ArrayList<>();
        //实例化数据
        for (int i = 1; i <= 50; i++) {
    
    
            News news = new News();
            news.setTitle("标题" + i);
            news.setContent(getRandomLengthContent("东营职业学院电子信息与传媒学院" + i + ". "));
            newsList.add(news);
        }
        return newsList;
    }
 
 
    /**
     * 随机生成不同长度的新闻内容
     * @param content
     * @return
     */
    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();
    }
 
    . . . 
}

Voici le mode double page.
Tout d'abord, ceux qui ont lu les premières lignes de code sur les premières pages doivent savoir que le nouveau dossier layout-sw600dp sous res sélectionnera automatiquement les fichiers sous ce dossier lorsque l'écran résolution est supérieure à 600. Créez un nouveau fichier activity_main sous le dossier.

<?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="horizontal">
 
    <fragment
        android:id="@+id/news_title_fragment"
        android:name="com.yiyajing.mypremission.fragment.NewsTitleFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />
 
    <FrameLayout
        android:id="@+id/news_content_layout"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3">
 
        <fragment
            android:id="@+id/news_content_fragment"
            android:name="com.yiyajing.mypremission.fragment.NewsContentFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
</LinearLayout>

On peut voir qu'en mode double page, nous avons introduit deux fragments en même temps, et placé les fragments de contenu d'actualités sous une mise en page FrameLayout, et l'id de cette mise en page est news_content_layout. Par conséquent, le mode double page peut être trouvé si cet identifiant peut être trouvé. Sinon, c'est le mode page simple. Dans le cas du mode double page, le système sélectionnera automatiquement cette mise en page.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_42349568/article/details/128995317
conseillé
Classement