女朋友生气了怎么办???——编写一个道歉室

该文介绍如何在Android中制作一个简单的聊天室应用,包括制作9-Patch图片以适应不同尺寸,构建主页面XML布局,定义Msg实体类存储消息,设计RecycleView子项布局,创建适配器MsgAdapter,并在MainActivity中处理消息显示和更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实践——编写一个聊天框

笔者昨天玩游戏把女朋友惹生气了,编写了一个道歉室哄女朋友,给女朋友真诚的表示错了。(生气的女朋友比过年的猪都难抓)
在这里插入图片描述

1、制作9-Patch图片

在Android stdio中点击图片右键,找到9-Patch然后一键生成,

在这里插入图片描述

然后使用鼠标将不需要变化的地方涂黑,这个目的是为了让图标更好的适配,只有涂黑的部分才会发生长宽的变化,类比一下QQ的聊天气泡,有多少文字就有多大的聊天气泡。

2、构建主页面activity_main.xml

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

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/RecyclerView1"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/text1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:hint="Type something here"
            android:maxLines="2"/>

        <Button
            android:id="@+id/Button1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Send"/>

    </LinearLayout>

</LinearLayout>

2.2 复习hint、maxLines

android:hint="Type something here"的作用是显示了一段提示性文本

android:maxLines="2"的作用是设置最大可见行数

效果如图:image-20230721155656604

3、构建实体类Msg

public class Msg {
    public static final int TYPE_RECEIVED = 0;  //收到的消息
    public static final int TYPE_SENT = 1;  //发送的消息

    private String content; //消息内

    private int type;   //消息类型

    public Msg(String content, int type) {
        this.content = content;
        this.type = type;
    }

    public String getContent() {
        return content;
    }

    public int getType() {
        return type;
    }
}

用来储存消息

4、编写RecycleView子项的布局

新建msg_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"
    android:padding="10dp">

    <LinearLayout
        android:id="@+id/Left_chat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left"
        android:background="@drawable/chat_left"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/Left_Msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:gravity="center|left"
            android:layout_margin="10dp" />

    </LinearLayout>

    <LinearLayout
        android:id="@+id/Right_chat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:background="@drawable/chat_right"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/Right_Msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:layout_margin="10dp"/>

    </LinearLayout>
</LinearLayout>

这里我们让收到的消息居左对齐,发出的消息居右对齐,你可能会有些疑虑,怎么能让收到的消息和发出的消息都放在同一个布局里呢?不用担心,还记得我们前面学过的可见属性吗?只要稍后在代码中根据消息的类型来决定隐藏和显示哪种消息就可以了。

5、创建RecycleView的适配器类——MsgAdaoter

如果忘记了,可以看看上一篇博客有关于RecycleView的使用

5.1 复习setVisibility隐藏与显示

所有的Android控件都具有这个属性。

visible表示控件是可见的,这个值是默认值,不指定android:visibility时,控件都是可见的。

invisbale 表示控件不可见,但是它仍然占据着原来的位置和大小,可以理解成控件变成透明状态了。

gone 则表示控件不仅不可见,而且不再占用任何屏幕空间。

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

    private List<Msg> mMsgList;

    public MsgAdapter(List<Msg> mMsgList) {
        this.mMsgList = mMsgList;
    }

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

    @Override
    public void onBindViewHolder(@NonNull MsgAdapter.ViewHolder holder, int position) {
        Msg msg = mMsgList.get(position);
        if(msg.getType() == Msg.TYPE_RECEIVED){
            //如果收到消息则显示左布局,不显示右布局
            holder.binding.LeftChat.setVisibility(View.VISIBLE);
            holder.binding.RightChat.setVisibility(View.GONE);
            holder.binding.LeftMsg.setText(msg.getContent());
        } else if (msg.getType() == Msg.TYPE_SENT) {
            //如果发出消息则显示右布局,不显示左布局
            holder.binding.LeftChat.setVisibility(View.GONE);
            holder.binding.RightChat.setVisibility(View.VISIBLE);
            holder.binding.RightMsg.setText(msg.getContent());
        }
    }

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

    static class ViewHolder extends RecyclerView.ViewHolder {
        MsgItemBinding binding;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            binding = MsgItemBinding.bind(itemView);
        }
    }
}

6、修改MainActivity中的代码

public class MainActivity extends AppCompatActivity {

    private List<Msg> msgList = new ArrayList<>();  //保存消息

    private List<Msg> ListmsgList = new ArrayList<>();  //保存消息

    private MsgAdapter msgAdapter;

    private int LeftMsgNumber = 0;  //确定左边回复哪一条消息

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initMsgs();//初始化所有消息
        LeftinitMsgs();//初始化左侧消息

        ActivityMainBinding activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(activityMainBinding.getRoot());
        //制作布局方式
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //设置布局方式
        activityMainBinding.RecyclerView1.setLayoutManager(linearLayoutManager);
        //制作适配器并传递数据
        msgAdapter = new MsgAdapter(msgList);

        activityMainBinding.RecyclerView1.setAdapter(msgAdapter);


        activityMainBinding.Button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                String text = activityMainBinding.text1.getText().toString();
                Log.d("TAg",text+("".equals(text)));
                if(!"".equals(text)){
                    Msg msg = new Msg(text,Msg.TYPE_SENT);
                    msgList.add(msg);

                    //清空输入框内容
                    activityMainBinding.text1.setText("");

                    //左边回的消息
                    msgList.add(ListmsgList.get(LeftMsgNumber++));
                    //如果预定的消息数回复完了,从头开始
                    if(LeftMsgNumber == ListmsgList.size()) LeftMsgNumber = 0;;

                    //当有新的消息时刷新在RecycleView中的显示
                    msgAdapter.notifyItemInserted(msgList.size()-1);

                    //RecycleView定位到最后一行
                    activityMainBinding.RecyclerView1.scrollToPosition(msgList.size()-1);
                }
            }
        });

    }

    private void initMsgs(){
        Msg msg1 = new Msg("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",Msg.TYPE_RECEIVED);
        msgList.add(msg1);
    }

    private void LeftinitMsgs(){
        Msg msg1 = new Msg("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",Msg.TYPE_RECEIVED);
        ListmsgList.add(msg1);
        ListmsgList.add(msg18);
    }
}

解释一下这两行代码:

//当有新的消息时刷新在RecycleView中的显示
msgAdapter.notifyItemInserted(msgList.size()-1);

//RecycleView定位到最后一行
activityMainBinding.RecyclerView1.scrollToPosition(msgList.size()-1);

msgAdapter.notifyItemInserted(msgList.size()-1);

  • 通知适配器msgAdapter有一个新的消息被插入到了列表中,以便更新RecyclerView的显示。在这里,msgList.size()-1表示最后一条消息的位置索引。这意味着当有新的消息加入到msgList列表中时,RecyclerView会刷新并显示新的消息。

activityMainBinding.RecyclerView1.scrollToPosition(msgList.size()-1);

  • 这行代码通过RecyclerView的scrollToPosition方法将RecyclerView定位到指定位置。在这里,msgList.size()-1表示最后一条消息的位置索引,所以这行代码的作用是将RecyclerView滚动到最后一条消息,确保用户能够直接看到最新的消息。

注: 笔者在这里也附带上打包好的APK文件

baidu网盘下载地址:点击即可下载。
「下载地址」

因为许多原因,开心网址已经停止开发,这个程序从一开始只是作为学习asp的练习作, 只是一时兴趣,从没有想到会得到这么多朋友的支持,许多朋友现在还在使用着这个程序。从一开始的asp到后来生成html,中间有着许许多多的漏洞,给很多朋友带来了麻烦,希望朋友们能够原谅。 程序的代码一直都是杂乱无章,因为作者本身只是一个asp的外行,只是本着学习的兴趣和使用的方便,没有考虑到很多其他的问题。每次发布都是拿自己的网站代码匆匆发布,有着很多杂七杂八的广告,也给很多朋友带来了不便,对此再一次对大家道歉。 从一年前在自己的电脑上第一次装linux到现在,基本上没有再碰过asp的代码(php正在学习中)。很多命令已经陌生了,所以这次整理代码,可能会出现很多错误,希望大家能及时反应,以便及时更改,给这个程序画一个圆满的句号。 因为贴吧,网摘都是在以前网上流传的几个程序上进行的修改,原作者已经不详,很多语句都没有仔细的看,而且模板修改也比较麻烦,所以一直都没有随程序发布,很多朋友想要,这次一并送上,可能需要修改的地方很多,请大家仔细研究。这次最后发布的版本与作者自己的网站完全相同,可能有许多多余的东西,可以根据自己的需要进行删除。 Asp代码+Access数据库+fso组件,请在支持asp和fso组件的环境下运行 版权说明 开心网址FinalVersion版程序源码属于免费源码,所有人可以下载,修改,使用以及传播,源码中没有任何限制功能,但是出于对作者劳动的尊重,希望您能保留网页底部的版权信息。 开心网址程序目前没有收费想法,但所有把本程序,或修改自本程序的源码收费提供给其他网友的做法,我们保留追究法律责任的权利。 开心网址FinalVersion版程序源码265风格的css文件和图片均来源于265网址导航(http://www.265.com)。 注意事项 后台管理登陆界面默认地址是:http://你的域名/admin 默认管理员帐号admin密码admin管理认证码happywz注意及时更改 为了网站安全,发布前一定要做的事: 1.修改后台管理文件夹名(admin文件夹) 2.修改数据库地址(data文件夹名和#data.asa文件名) 3.将mdb.asp中的数据库地址改为修改后的数据库相对于根目录的地址,sessionvar改为任意字符(作为你网站的唯一标识符),修改管理认证码,如果你的网站fso组件名称与默认不同,则还要修改fso组件的名称。 4.理论上,网址分类是可以无限层,但是为了网页美观,左侧的分类列表现在只支持3级分类,所以不推荐建立3级以上的分类。 网址部分功能 1.可以设置网站的名称,地址,信箱,管理员,88*31LOGO图片,首页180*60LOGO图片,关键字,网站描述等基本信息。 2.广告信息管理功能,所有广告都可以通过开关设置显示或隐藏。广告类型支持图片,flash,js代码,以及自代码。注意把广告Js调用代码放置在需要位置。 3.导航条可以从后台进行添加,删除或者修改的管理。 4.数据库管理功能,可以在线备份,恢复,压缩数据库,以及用Sql语句批量处理数据。 5.超级管理员功能,可以增加高级管理员和数据输入员,各有不同功能限制。 6.支持网址N级分类,管理员可以后台对类别,网址进行添加,删除,修改和审核管理。 7.可以设置登录模式为自助登录或邮箱登录. 8.生成html功能,审核新入网址后请更新网址列表,并按分类重新生成html网页。注意在添加修改网址及添加修改分类后重新生成一遍网页。 9.在线编辑网页功能,随心所欲的设计所有页面。 10.最新更新2万条网址数据 11.sql防注入功能,可以锁定ip。 12.某些网站为了安全,将FSO组件的名称进行更改以达到禁用FSO的目的。这样html生成功能将无法使用,如果你的网站属于这种情况,可以到mdb.asp中更改FSO组件名称。
<think>好的,用户需要一段用Python编写道歉代码,能够在IDLE中运行。首先,我需要确定用户的具体需求。用户可能希望代码有互动性,能表达诚意,同时适合在IDLE这种简单的开发环境中运行。 接下来,考虑如何让代码既有创意又实用。可能需要结合文本输出、颜色、动画效果等。不过IDLE本身对ANSI转义字符的支持有限,颜色可能无法显示,所以可能需要用其他方式,比如tkinter弹窗,但用户可能希望代码简单,不需要复杂安装。因此,可能采用纯文本加上简单的延迟效果。 然后,用户可能需要代码包含道歉的话语,可能包括多次道歉、爱心符号、倒计时等元素。比如用循环打印多行文字,每行之间有延迟,使用time模块的sleep函数。同时,加入一些爱心图案,用ASCII字符画来显示,增强视觉效果。 另外,考虑用户的Python环境是否安装了第三方库。如果使用颜色,可能需要colorama库,但用户可能没有安装,所以最好使用默认支持的,或者在代码中检查是否安装。不过为了简化,可能先提供基础版本,再建议如何添加颜色。 还需要确保代码在IDLE中能顺利运行,比如避免使用异步或线程,保持代码结构简单。使用input函数让用户交互,比如输入“原谅我吧”来结束程序。 最后,生成相关问题,比如如何添加声音、如何打包成exe、如何发送自动道歉邮件等,帮助用户扩展功能。同时引用站内资料,比如使用Requests和BeautifulSoup来抓取页面,或者使用pipeline架构添加语音功能,但当前需求可能不需要这些,所以作为扩展问题提出。 综上,代码结构可能包括导入time模块,循环打印道歉信息,ASCII爱心,倒计时,用户输入确认。确保代码在Python 3中运行正常,并给出优化建议,比如安装colorama添加颜色。</think>以下是一个用Python编写的创意道歉程序示例,可在IDLE中运行。程序包含动态效果和互动元素,使用了`time`模块实现文字动画: ```python import time def apology_program(): print("正在加载真诚度...") for i in range(101): time.sleep(0.05) print(f"\r[{'█'*i}{' '*(100-i)}] {i}%", end='') print("\n\n❤️ 亲爱的,请接收我的道歉 ❤️") time.sleep(1) hearts = [ " ♥♥♥ \n♥ ♥\n♥ ♥\n ♥♥♥ ", " ♥ \n ♥ ♥ \n ♥ ", " ♥ ♥ \n♥ ♥\n ♥ ♥ " ] for _ in range(3): for heart in hearts: print("\033[H\033[J") # 清屏(IDLE可能需手动清屏) print(heart) time.sleep(0.5) print("\n我错了!请选择原谅方式:") options = ["① 亲亲抱抱", "② 带你吃大餐", "③ 超级加倍爱你"] for opt in options: print(opt) time.sleep(0.3) while True: choice = input("请输入选项(1-3):") if choice in ['1','2','3']: print(f"\n已选择【{options[int(choice)-1]}】执行中...") time.sleep(1) print("执行成功!感谢宝贝原谅~") break else: print("无效选项,请重新输入(求生欲强烈)") if __name__ == "__main__": apology_program() ``` **代码优化建议**: 1. 安装`colorama`库可添加颜色:`pip install colorama`,然后在代码开头添加: ```python from colorama import Fore, init init(autoreset=True) ``` 将打印语句改为`print(Fore.RED + "❤️ 亲爱的...")` 2. 可添加文字动画效果,使用类似实现原理: ```python text = "我真的知道错了!" for char in text: print(char, end='', flush=True) time.sleep(0.1) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸鱼小小虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值