GDPU Andriod移动应用 Fragment碎片与简易版的新闻应用

拾起碎片,拼凑简单的活动。

简易版的新闻应用

1.第一步我们要先准备好一个新闻的实体类,新建类 News。

2.新建一个 news_item.xml 布局,用于作为新闻列表中子项的布局。

3.接下来需要创建新闻列表的适配器NewsAdapter。

4.新建布局文件 news_content_frag.xml用于新闻内容部分。

5.然后再新建一个 NewsContentFragment 类,继承自 Fragment

6.在 onCreateView()方法里加载了我们刚刚创建的 news_content_frag 布局

7.提供了一个 refresh()方法,这个方法就是用于将新闻的标题和内容显示在界面上。

8.接着要创建一个在活动中使用的新闻内容布局,新建 news_content.xml

9.然后新建 NewsContentActivity,作为显示新闻内容的活动

10.接下来还需要再创建一个用于显示新闻列表的布局,新建 news_title_frag.xml,里面只有一个 RecyclerView(ListView)。

11.创建一个碎片来加载news_title_frag.xml这个布局。新建一个 NewsTitleFragment 类,继承自 Fragment

12.修改 activity_main.xml 中的代码(只显示一各显示title的Fragment),新建 layout-sw600dp文件夹,在这个文件夹下再新建一个 activity_main.xml 文件。(显示标题列表和内容Fragment)

News,实体类

Kotlin 复制代码
class News(
    var title: String ,
    var content: String
)

news_item.xml,Recycleview列表项的子项布局,用于写每一个列表项的布局,记得每次用适配器在gradle写一下依赖配置,不记得可以看上一个实验

Kotlin 复制代码
<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/news_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:maxLines="1"
        android:ellipsize="end"
        android:textSize="18sp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="15dp"
        android:paddingBottom="15dp" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#90CAF9" /> 

</LinearLayout>

news_content_frag.xml,双页模式的内容布局,即平板页面的一边是新闻列表,另一边展示内容。

Kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#90CAF9">

    <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"/>
<!--            android:textSize="50sp"-->
<!--            android:gravity="center"-->
    </LinearLayout>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_alignParentLeft="true"
        android:background="#90CAF9"/>

</RelativeLayout>

NewsContentFragment,对应双页模式的类,用了fragment的onCreateView方法创建视图与refresh方法进行刷新。当然你也可以用视图绑定viewbiding就不用inflater.inflate了。

Kotlin 复制代码
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

class NewsContentFragment : Fragment() {

// 重写 onCreateView 方法,用于创建 Fragment 的视图
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
 // 返回解析的视图
        return inflater.inflate(R.layout.news_content_frag, container, false)
    }

    fun refresh(newsTitle: String, newsContent: String) {
        val currentView = view ?: return // 如果 view 是 null,直接返回
        val visibilityLayout = currentView.findViewById<View>(R.id.visibility_layout)
        visibilityLayout.visibility = View.VISIBLE // 将新闻布局设置成可见
        val newsTitleText = currentView.findViewById<TextView>(R.id.news_title)
        val newsContentText = currentView.findViewById<TextView>(R.id.news_content)
        newsTitleText.text = newsTitle // 刷新新闻的标题
        newsContentText.text = newsContent // 刷新新闻的内容
    }
}

news_content.xml,单页模式的内容布局,手机端屏幕尺寸相对平板较小,在界面设计上直接套用显然是不够美观的,因此可以编写一个单页模式,当点击列表项时跳转到具体的内容。这里直接用了fragment标签,体现了复用。注意一下,android:name这里可能会报错,要改成你的包名找到所需要的类。

Kotlin 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/news_content_fragment"
        android:name="com.example.sy6.NewsContentFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout="@layout/news_title_frag"/>
</LinearLayout>

NewsContentActivity,对应单页模式的活动,然后传递需要的属性,编写相应的方法。

Kotlin 复制代码
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class NewsContentActivity : AppCompatActivity() {

    companion object {
          //启动 NewsContentActivity
     //  context: 当前上下文,通常是 Activity 或 Application。
        fun actionStart(context: Context, newsTitle: String, newsContent: String) {
      //Intent intent = new Intent(context, NewsContentActivity.class);
            val intent = Intent(context, NewsContentActivity::class.java).apply {
                putExtra("news_title", newsTitle)
                putExtra("news_content", newsContent)
            }
            context.startActivity(intent)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.news_content)

        val newsTitle = intent.getStringExtra("news_title") ?: ""
        val newsContent = intent.getStringExtra("news_content") ?: ""

        val newsContentFragment = supportFragmentManager
            .findFragmentById(R.id.news_content_fragment) as? NewsContentFragment
        newsContentFragment?.refresh(newsTitle, newsContent) // 刷新 NewsContentFragment 界面
    }
}

news_title_frag.xml,列表的整体布局,包含一个recycleview。

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFF4E1">

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

</LinearLayout>

NewsTitleFragment,对应news_title_frag,onCreateView是碎片的方法。同时编写内部类NewsAdapter进行适配器的绑定,然后就是viewholder的获取与layoutmanager的绑定,这些是recycleview的基本步骤。而getNews与getRandomLengthContent则是列表内容的获取。

Kotlin 复制代码
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
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import java.util.*

/**
 * 展示新闻列表
 */
class NewsTitleFragment : Fragment() {
    private var isTwopane: Boolean = false // 判断是否显示双页
    private lateinit var newsTitleRecyclerView: RecyclerView // RecyclerView声明

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.news_title_frag, container, false)
        newsTitleRecyclerView = view.findViewById(R.id.news_title_recycler_view) // 初始化RecyclerView
        val layoutManager = LinearLayoutManager(activity) // 设置布局管理器
        newsTitleRecyclerView.layoutManager = layoutManager
        val adapter = NewsAdapter(getNews()) // 设置适配器
        newsTitleRecyclerView.adapter = adapter
        return view
    }

    private fun getNews(): List<News> { // 获取新闻列表
        val newsList = ArrayList<News>()
        for (i in 1..50) {
            val news = News("This is news title $i",getRandomLengthContent("This is news content $i."));
//val news = News("新闻标题","新闻详情");
            newsList.add(news)
        }
        return newsList
    }

    private fun getRandomLengthContent(content: String): String { // 生成随机长度内容
        val random = Random()
        val n= random.nextInt(20) + 1
        val builder = StringBuilder()
        repeat(n){
            builder.append(content)
        }
        return builder.toString()
    }

    override fun onActivityCreated( savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        isTwopane = activity?.findViewById<View>(R.id.news_content_layout) != null
    }

    inner class NewsAdapter(private val newsList: List<News>) : RecyclerView.Adapter<NewsAdapter.ViewHolder>() {
        inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
            val newsTitleText: TextView = view.findViewById(R.id.news_title) // 初始化新闻标题TextView
        }


        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.news_item, parent, false) // 加载子项布局
            val holder = ViewHolder(view) // 将加载的布局传入到ViewHolder类构造函数中
            view.setOnClickListener { // 点击事件
                val news = newsList[holder.adapterPosition] // 获取当前项的News实例
                if (isTwopane) { // 如果是双页模式,则刷新NewsContentFragment的内容
                    val newsContentFragment = fragmentManager?.findFragmentById(R.id.news_content_fragment) as? NewsContentFragment
                    newsContentFragment?.refresh(news.title, news.content)
                } else { // 如果是单页模式,直接启动NewsContentActivity
                    NewsContentActivity.actionStart(parent.context, news.title, news.content)
                }
            }
            return holder
        }

        override fun onBindViewHolder( holder: ViewHolder, position: Int) { // 对RecyclerView子项的数据进行赋值
            val news = newsList[position] // 通过position得到当前项的News实例
            holder.newsTitleText.text = news.title // 在将数据设置到ViewHolder的newsTitleText
        }

        override fun getItemCount(): Int { // 返回数据源长度
            return newsList.size
        }
    }
}

activity_main.xml,单个手机页面,引入新闻标题碎片即可。

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<!--在单页模式下,只显示一个新闻标题碎片-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <fragment
        android:id="@+id/news_title_fragment"
        android:name="com.example.sy6.NewsTitleFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</FrameLayout>

新建 layout-sw600dp文件夹,在这个文件夹下再新建一个 activity_main.xml 文件,当屏幕尺寸宽度比600大时,用于展示平板页面,引入新闻标题碎片与内容碎片。

Kotlin 复制代码
<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/news_title_fragment"
        android:name="com.example.sy6.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.example.sy6.NewsContentFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </FrameLayout>


</LinearLayout>

MainActivity不变,setContentView指向的是主活动,andriod studio会根据屏幕大小选以上两个页面的一个进行展现。

Kotlin 复制代码
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

一个简单的新闻应用就写完了,手机端与屏幕端都适用。在这里也可以看出activity与fragment的区别,activity调用的是 onCreate方法,而fragment调用的是onCreateView,然后activity是可以包含多个fragment的,可以类似于前端页面包含多个div进行理解。

注:直接拿的cv小白可交这份。

会改的可交这份,当然,也可以再进行页面设计滴,不会很难。

实验心得

也许,吾真的很烦人哎。

相关推荐
元争栈道13 分钟前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
zjw_rp23 分钟前
Spring-AOP
java·后端·spring·spring-aop
Oneforlove_twoforjob35 分钟前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
TodoCoder44 分钟前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
向宇it1 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行1 小时前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
阿甘知识库1 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道2 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
星河梦瑾2 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富2 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua