微信界面开发

一、效果实现

二、功能说明

需要实现一个类似微信的简单应用框架,包括以下功能:

  • 界面跳转功能:设置四个主界面,分别是“聊天”、“联系人”、“发现”和“我的”。用户点击相应的图标,可以在这些界面之间自由切换,每次点击会跳转到对应的页面。

  • 联系人展示与数据绑定:在“联系人”界面展示一个联系人列表(用商品图片代替联系人图标)。当用户点击某个商品图片时,能够显示对应的详细信息。

  • 背景音乐功能:为“联系人”界面添加背景音乐,当用户进入“联系人”界面时自动播放音乐,退出该界面时音乐自动停止。

故需要实现的功能:

1.activity之间的跳转

2.数据的动态连接

3.背景音乐的实现

三、功能实现 

1.跳转功能
1.1界面之间的跳转涉及以下xml文件

微信主界面设计:

在主界面的布局中,采用了 XML 文件的嵌套设计。界面整体分为三个部分:

(1)顶部区域:顶部显示“我的微信”标题部分,其布局定义在单独的 layout_top.xml 文件中

(2)中间内容区域:用于显示主功能界面的具体内容,支持动态切换。

(3)底部导航栏:底部包含四个功能图标,分别对应“聊天”、“联系人”、“发现”和“我的”模块,其布局封装在 layout_bottom.xml 文件中。

    顶部区域

底部导航栏

四个跳转界面的布局

 布局框架搭好后,进行跳转代码的编写

MainActivity_fragment 中定义了四个底部导航按钮,分别对应四个微信功能图标。通过 showFragment()Fragmenthide() 方法,管理各功能页面的显示与隐藏。结合一个 if-else 判断逻辑,实现了用户点击任意图标时,能够切换到对应功能界面的效果。

package com.example.myapplication;

import static com.example.myapplication.R.id.bottom_layout1;
import static com.example.myapplication.R.id.bottom_layout2;
import static com.example.myapplication.R.id.bottom_layout3;
import static com.example.myapplication.R.id.bottom_layout4;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

public class MainActivity_fragment extends AppCompatActivity implements View.OnClickListener {
    Fragment fragment1, fragment2, fragment3, fragment4;
    LinearLayout layout1, layout2, layout3, layout4;
    FragmentManager manager;
    FragmentTransaction transaction;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_fragment);

        layout1 = findViewById(R.id.bottom_layout1);
        layout2 = findViewById(R.id.bottom_layout2);
        layout3 = findViewById(R.id.bottom_layout3);
        layout4 = findViewById(R.id.bottom_layout4);


        fragment1 = new BlankFragment1();
        fragment2 = new BlankFragment2();
        fragment3 = new BlankFragment3();
        fragment4 = new BlankFragment4();


        manager = getSupportFragmentManager();
        transaction = manager.beginTransaction();

        initial();

        fragementhide();

        transaction.show(fragment1);
        transaction.commit();


        layout1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                transaction = manager.beginTransaction();
                fragementhide();
                transaction.show(fragment1);
                transaction.commit();
            }
        });

        layout2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                transaction = manager.beginTransaction();
                fragementhide();
                transaction.show(fragment2);
                transaction.commit();
            }
        });

        layout3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                transaction = manager.beginTransaction();
                fragementhide();
                transaction.show(fragment3);
                transaction.commit();
            }
        });

        layout4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                transaction = manager.beginTransaction();
                fragementhide();
                transaction.show(fragment4);
                transaction.commit();
            }
        });


    }
    public void initial() {
        transaction.add(R.id.framelayout1, fragment1);
        transaction.add(R.id.framelayout1, fragment2);
        transaction.add(R.id.framelayout1, fragment3);
        transaction.add(R.id.framelayout1, fragment4);

    }
    public void fragementhide() {
        transaction.hide(fragment1);
        transaction.hide(fragment2);
        transaction.hide(fragment3);
        transaction.hide(fragment4);

    }
    public void showfragement(Fragment fragment) {
        transaction = manager.beginTransaction();
        fragementhide();
        transaction.show(fragment);
        transaction.commit();
    }
    @Override
    public void onClick(View view) {
        if(view.getId() == bottom_layout1)
        {fragementhide();showfragement(fragment1);}
        else if(view.getId() == bottom_layout2)
        {fragementhide();showfragement(fragment2);}
        else if(view.getId() == bottom_layout3)
        {fragementhide();showfragement(fragment3);}
        else if(view.getId() ==bottom_layout4)
        {fragementhide();showfragement(fragment4);}

    }
}
1.2联系人界面的跳转

涉及intent类

intent

Intent 类是 Android 中用于在不同组件(如 Activity、Service、BroadcastReceiver)之间传递数据和触发操作的重要工具。它的主要作用包括以下几个方面

启动组件:用于启动新的 Activity 或 Service,实现页面跳转或启动后台任务。
例如,startActivity(intent) 用于打开一个新页面。


传递数据:可通过 putExtra() 方法将数据附加到 Intent 中,并在目标组件中通过 getExtra() 方法获取数据。例如,在页面间传递用户输入的数据或状态信息。


广播消息:用于向系统或应用中的其他部分发送广播消息,配合 BroadcastReceiver 使用。


隐式意图调用:通过隐式 Intent 指定动作(如查看网页、拨打电话)和数据类型,让系统匹配符合条件的组件来完成操作。
示例
启动一个新页面并传递数据

Intent intent = new Intent(CurrentActivity.this, TargetActivity.class);
intent.putExtra("key", "value");  // 附加数据
startActivity(intent);            // 启动目标Activity

获取传递过来的数据:

Intent intent = getIntent();
String value = intent.getStringExtra("key");
2.连接数据 
2.1创建列表

recycleview 

 RecyclerView 是 Android 提供的一种高级、灵活的视图组件,用于高效地显示大量数据集合(如列表或网格)。它是 ListViewGridView 的升级版本,具备更强的功能和更高的性能。

(1)高效复用:通过 ViewHolder 模式优化性能,适用于大数据量场景。

(2)灵活布局:支持线性、网格和瀑布流布局,可自定义显示样式。

(3)扩展性强:支持自定义动画、分隔线装饰、拖拽排序和滑动删除等功能。

(4)分页加载与滑动监听:方便实现动态数据加载。

2.2数据存储

创建list1列表进行数据存储

package com.example.myapplication;

import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BlankFragment2 extends Fragment {

    private Context context;
    private List< Map<String,Object>> list;
    public RecyclerView.Adapter adapter1;
    List<Map<String,Object>> list1;
    private RecyclerView recyclerView;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view= inflater.inflate(R.layout.activity_main3, container, false);

        context=getContext();
        recyclerView=view.findViewById(R.id.recyclerView);

        int[] phonename={R.drawable.p1,R.drawable.p2,R.drawable.p3};
        String[] price={"1000","2000","3000"};
        String[] config={"sss","qqq","rrr"};

        list1 =new ArrayList<Map<String,Object>>();

        for(int i=0;i<phonename.length;i++)
        {
            Map<String,Object> map=new HashMap<>();
            map.put("name",phonename[i]);
            map.put("price",price[i]);
            map.put("config",config[i]);
            list1.add(map);
        }

        adapter1=new Adapter(context,list1);
        recyclerView.setAdapter(adapter1);
        LinearLayoutManager manager=new LinearLayoutManager(context);
        recyclerView.setLayoutManager(manager);
        // Inflate the layout for this fragment

        return view;
    }

}
2.3绑定数据 

Adapter 中,ViewHolder(通常简称为 holder)的作用是用于高效绑定视图和数据。它通过缓存子视图,避免重复调用 findViewById(),从而提高性能。

工作机制

(1)视图创建AdapteronCreateViewHolder() 方法创建 ViewHolder 对象,并将布局视图绑定到 ViewHolder 中。

(2)数据绑定:在 onBindViewHolder() 方法中,holder 被用来将数据绑定到具体的视图组件(如 TextViewImageView 等)。

package com.example.myapplication;

import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;


import java.util.List;
import java.util.Map;

public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {

    private Context context;
    private View inflater;
    private List< Map<String,Object>> list;
    ActivityResultLauncher<Intent> launcher;
    public Adapter(Context context, List<Map<String,Object>> list)
    {
        this.context=context;
        this.list=list;
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        inflater=LayoutInflater.from(context).inflate(R.layout.layout_item,viewGroup,false);
        MyViewHolder holder=new MyViewHolder(inflater);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder myViewHolder, int j) {
        myViewHolder.imageView.setImageResource(Integer.parseInt(list.get(j).get("name").toString()));

        //myViewHolder.textView1.setText(list.get(j).get("name").toString());
        String str1=list.get(j).get("price").toString();
        String str2=list.get(j).get("config").toString();
        myViewHolder.textView2.setText(str1);
        myViewHolder.textView3.setText(str2);

//        launcher=registerForActivityResult(
//                new ActivityResultContracts.StartActivityForResult(),
//                new ActivityResultCallback<ActivityResult>() {
//                    @Override
//                    public void onActivityResult(ActivityResult result) {
//                        if(result.getResultCode()==666){
//                            String str1=result.getData().getStringExtra("result");
//                            textview.setText(str1);
//                        }
//                    }
//                }
//        );


        myViewHolder.imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(context,MainActivity_cantact_detail.class);
               intent.putExtra("price",str1);
                intent.putExtra("config",str2);
                context.startActivity(intent);
                //launcher.launch(intent);
            }
        });
    }

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

    static class MyViewHolder extends RecyclerView.ViewHolder{
        TextView textView1,textView2,textView3;
        ImageView imageView;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            imageView=itemView.findViewById(R.id.rc_imageView);
            //textView1 =itemView.findViewById(R.id.rc_textview1);
            textView2 =itemView.findViewById(R.id.rc_textview2);
            textView3 =itemView.findViewById(R.id.rc_textview3);
        }
    }

}

页面展示:

3.添加背景音乐

添加music.mp3(保证音乐可放,无损坏)

绑定式服务音乐播放代码

package com.example.myapplication;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
    MediaPlayer mediaPlayer;
    public MyService() {
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mediaPlayer=MediaPlayer.create(this,R.raw.music);
        mediaPlayer.start();
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
       // throw new UnsupportedOperationException("Not yet implemented");
        Log.d("zyq","MYservice onbind...");
        Mybinder binder=new Mybinder();
        return binder;
    }
    @Override
    public void onDestroy() {
        Log.d("zyq","MYservice destroy....");
        mediaPlayer.stop();
        super.onDestroy();
    }
    public class Mybinder extends Binder{
        public Mybinder() {
            mediaPlayer=MediaPlayer.create(getApplicationContext(),R.raw.music);
            mediaPlayer.start();
        }
    }
}

音乐服务的连接与断开

package com.example.myapplication;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity_cantact_detail extends AppCompatActivity {

    TextView textView;
    MyService.Mybinder mybinder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main_cantact_detail);
        textView=findViewById(R.id.textView_detail);
        String str=getIntent().getStringExtra("price")+"/"+
                getIntent().getStringExtra("config");
        textView.setText(str);

        Intent intent=new Intent(this,MyService.class);
        ServiceConnection connection=new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                Log.d("zyq","onserviceconnect...");
                mybinder=(MyService.Mybinder) iBinder;


            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                Log.d("zyq","onserviceconnect...");
                mybinder=null;
            }
        };
        this.bindService(intent,connection, Context.BIND_AUTO_CREATE);
//        this.startService(intent);

    }
}

绑定式服务启动:使用 bindService() 方法启动服务,与 Activity 组件的生命周期绑定。通过绑定后,可以在 Activity 中直接调用服务的接口来控制音乐播放和停止。绑定的服务在组件销毁时会自动停止。

四、总结 

  • 问题描述
    Fragment 切换过程中,由于重新加载导致屏幕闪烁,用户体验较差。
  • 解决方法
    FragmentTransaction 中,初始化时将所有 Fragment 添加到布局并隐藏,切换时仅显示目标 Fragment,避免重复创建。
  • 问题描述
    数据在 RecyclerView 中未正确显示,或图片资源加载错误。
  • 解决方法
    检查 Adapter 中数据绑定逻辑,确保数据源和视图组件一一对应;对于图片资源,使用 setImageResource() 方法时需要转换为整数。
  • 问题描述
    页面退出时,音乐服务仍在后台运行,导致资源浪费。
  • 解决方法
    在页面销毁时(onDestroy() 方法中),确保调用 unbindService()stopService() 停止服务;在服务类中重写 onDestroy(),确保资源彻底释放。
  • 问题描述
    当页面反复切换时,音乐会多次重复播放。
  • 解决方法
    在服务启动时检查 MediaPlayer 的状态,确保未重复初始化;例如:

    if (mediaPlayer == null) { mediaPlayer = MediaPlayer.create(this, R.raw.music); }

  • 问题描述
    在不同屏幕尺寸的设备上,底部导航栏或 RecyclerView 内容显示异常。
  • 解决方法
    使用约束布局(ConstraintLayout)替代传统线性布局,并结合 dpsp 单位设计界面,确保布局适配性。

本项目通过 Fragment 管理界面、RecyclerView 动态加载数据以及绑定式服务播放背景音乐,构建了一个高效、灵活的微信功能框架。

 My Application: 安卓项目代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值