主頁 > 移動端開發 > Xamarin.Forms ChatKit +Socket實作即時通訊

Xamarin.Forms ChatKit +Socket實作即時通訊

2021-09-10 09:43:53 移動端開發

Xamarin.Forms ChatKit 的使用 快速搭建即時通訊 UI

大家完成好,本期為大家實作 Android 端 SocketChat 的實作(需要原始碼請滑到最下面有博主通訊方式)

專案介紹:
ChatKit 控制元件來源:
https://github.com/jingliancui/XamarinFormsChatKitSample
通信組件:Socket

組成部分:服務端(PC,Winforms) 客戶端(PC,Winfrom,Xamarin.Forms Android)

畫個簡單的實作草圖:
在這里插入圖片描述
看過這張圖相信會有點輕微的理解:
下面看代碼實作:

第一步安裝 依賴包

安裝 NewGet 依賴包:
Install-Package XamarinLibrary.Xamarin.Android.ChatKit -Version 0.3.3
這個是 類似 QQ的聊天 UI

第二步 撰寫UI

在這里插入圖片描述
在這里插入圖片描述
代碼量太多 就不一一展示
貼上重要代碼:

Socket Client Code:

創建 一個單例XamarinSockectClient 類 防止客戶端重復創建

0000100020003 在線串列協議頭 ,

000200030006 好友訊息協議頭

 /// <summary>
    /// Sockect通訊客戶端  
    /// </summary>
    public class XamarinSockectClient
    {

        private static XamarinSockectClient _Singleton = null;
        public static XamarinSockectClient CreateInstance()
        {
            if (_Singleton == null)
            {
                _Singleton = new XamarinSockectClient();
            }
            return _Singleton;
        }
        public static XamarinSockectClient CreateInstance(string Ip, string Port)
        {
            if (_Singleton == null)
            {
                _Singleton = new XamarinSockectClient(Ip, Port);
            }
            return _Singleton;
        }

      

        public string ServerIp = "192.168.1.105";
        public string ServerPort = "9000";
        //public XamarinSockectClient()
        //{
        //    XamarinConnectToServer();
        //}

        public XamarinSockectClient(string Ip = "192.168.1.105", string Port = "9000")
        {
            ServerIp = Ip;
            ServerPort = Port;
            XamarinConnectToServer();
        }
        Socket socketClient = null;
        Thread threadClient = null;

        public const int SendBufferSize = 2 * 1024;
        public const int ReceiveBufferSize = 8 * 1024;

        private void XamarinConnectToServer()
        {
            //定義一個套位元組監聽  包含3個引數(IP4尋址協議,流式連接,TCP協議)
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //獲取文本框輸入的服務端IP和Port
            IPAddress serverIPAddress = IPAddress.Parse(ServerIp);
            int serverPort = int.Parse(ServerPort);
            IPEndPoint endpoint = new IPEndPoint(serverIPAddress, serverPort);
            //向指定的ip和埠號的服務端發送連接請求 用的方法是Connect 不是Bind
            socketClient.Connect(endpoint);
            //創建一個新執行緒 用于監聽服務端發來的資訊
            threadClient = new Thread(RecMsg);
            //將表單執行緒設定為與后臺同步
            threadClient.IsBackground = true;
            //啟動執行緒
            threadClient.Start();
            //登錄成功
            //txtMsg.AppendText("已與服務端建立連接,可以開始通信...\r\n");
            // btnConnectToServer.Enabled = false;
        }


        /// <summary>
        /// 接受服務端發來資訊的方法
        /// </summary>
        private void RecMsg()
        {
            while (true) //持續監聽服務端發來的訊息
            {
                string strRecMsg = null;
                int length = 0;
                byte[] buffer = new byte[SendBufferSize];
                try
                {
                    //將客戶端套接字接收到的位元組陣列存入記憶體緩沖區, 并獲取其長度
                    length = socketClient.Receive(buffer);
                }
                catch (SocketException ex)
                {
                    // txtMsg.AppendText("套接字例外訊息:" + ex.Message + "\r\n");
                    //    txtMsg.AppendText("服務端已斷開連接\r\n");
                    break;
                }
                catch (Exception ex)
                {
                    // txtMsg.AppendText("系統例外訊息: " + ex.Message + "\r\n");
                    break;
                }
                //將套接字獲取到的位元組陣列轉換為人可以看懂的字串
                strRecMsg = Encoding.UTF8.GetString(buffer, 0, length);             
               string[] ServerValue= strRecMsg.Split('*');
                switch (ServerValue[0])
                {
                    case "0000100020003":
                        if (DevHelp.DeviceHelp.devDelegateUpdateUi != null)
                        {                     
                            DevHelp.DeviceHelp.devDelegateUpdateUi.InitUI(ServerValue[1]);                     
                        }
                        break;
                    case "000200030006":
                        if (DevHelp.DeviceHelp.devDelegateMessagesList != null)
                        {
                            DevHelp.DeviceHelp.devDelegateMessagesList.AddMsg(ServerValue[1]);
                        }
                        break;
                    default:
                        break;
                }
                //JsonConvert.DeserializeObject<MessageAmanager>()

                //將文本框輸入的資訊附加到txtMsg中  并顯示 誰,什么時間,換行,發送了什么資訊 再換行
                //  txtMsg.AppendText("服務端在 " + GetCurrentTime() + " 給您發送了:\r\n" + strRecMsg + "\r\n");
            }
        }

        /// <summary>
        /// 發送字串資訊到服務端的方法
        /// </summary>
        private void ClientSendMsg(string sendMsg, byte symbol)
        {
            byte[] arrClientMsg = Encoding.UTF8.GetBytes(sendMsg);
            //實際發送的位元組陣列比實際輸入的長度多1 用于存取識別符號
            byte[] arrClientSendMsg = new byte[arrClientMsg.Length + 1];
            arrClientSendMsg[0] = symbol;  //在索引為0的位置上添加一個識別符號
            Buffer.BlockCopy(arrClientMsg, 0, arrClientSendMsg, 1, arrClientMsg.Length);

            socketClient.Send(arrClientSendMsg);
            // txtMsg.AppendText("SoFlash:" + GetCurrentTime() + "\r\n" + sendMsg + "\r\n");
        }

        //向服務端發送資訊
        public void XamarinSend(string Message)
        {
            ClientSendMsg(Message, 0);
        }

        //獲取在線用戶資訊
        public void XamarinGetUserInfo()
        {
            ClientSendMsg("001001001", 5);
        }

        //發送登錄資訊
        public void XamarinSendUserLogin()
        {
            string MyLogin = XamarinMessageAmanager("", $"{DeviceHelp.MyUserID}@{DevHelp.DeviceHelp.MyUserName}");
            ClientSendMsg($"002002002#{MyLogin}", 4);
        }

        快捷鍵 Enter 發送資訊
        //private void txtCMsg_KeyDown(object sender, KeyEventArgs e)
        //{   //當游標位于輸入文本框上的情況下 發送資訊的熱鍵為回車鍵Enter 
        //    if (e.KeyCode == Keys.Enter)
        //    {
        //        //則呼叫客戶端向服務端發送資訊的方法
        //        ClientSendMsg(txtCMsg.Text, 0);
        //    }
        //}

        string filePath = null;   //檔案的全路徑
        string fileName = null;   //檔案名稱(不包含路徑) 
        選擇要發送的檔案
        //private void XamarinSelectFile(object sender, EventArgs e)
        //{
        //    OpenFileDialog ofDialog = new OpenFileDialog();
        //    if (ofDialog.ShowDialog(this) == DialogResult.OK)
        //    {
        //        fileName = ofDialog.SafeFileName; //獲取選取檔案的檔案名
        //        txtFileName.Text = fileName;      //將檔案名顯示在文本框上 
        //        filePath = ofDialog.FileName;     //獲取包含檔案名的全路徑
        //    }
        //}

        /// <summary>
        /// 發送檔案的方法
        /// </summary>
        /// <param name="fileFullPath">檔案全路徑(包含檔案名稱)</param>
        private void XamarinSendFile(string fileFullPath)
        {
            if (string.IsNullOrEmpty(fileFullPath))
            {
                // MessageBox.Show(@"請選擇需要發送的檔案!");
                return;
            }

            //發送檔案之前 將檔案名字和長度發送過去
            long fileLength = new FileInfo(fileFullPath).Length;
            string totalMsg = string.Format("{0}-{1}", fileName, fileLength);
            ClientSendMsg(totalMsg, 2);


            //發送檔案
            byte[] buffer = new byte[SendBufferSize];

            using (FileStream fs = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read))
            {
                int readLength = 0;
                bool firstRead = true;
                long sentFileLength = 0;
                while ((readLength = fs.Read(buffer, 0, buffer.Length)) > 0 && sentFileLength < fileLength)
                {
                    sentFileLength += readLength;
                    //在第一次發送的位元組流上加個前綴1
                    if (firstRead)
                    {
                        byte[] firstBuffer = new byte[readLength + 1];
                        firstBuffer[0] = 1; //告訴機器該發送的位元組陣列為檔案
                        Buffer.BlockCopy(buffer, 0, firstBuffer, 1, readLength);

                        socketClient.Send(firstBuffer, 0, readLength + 1, SocketFlags.None);

                        firstRead = false;
                        continue;
                    }
                    //之后發送的均為直接讀取的位元組流
                    socketClient.Send(buffer, 0, readLength, SocketFlags.None);
                }
                fs.Close();
            }
            //   txtMsg.AppendText("SoFlash:" + GetCurrentTime() + "\r\n您發送了檔案:" + fileName + "\r\n");
        }

        //點擊檔案發送按鈕 發送檔案
        private void btnSendFile_Click(object sender, EventArgs e)
        {
            XamarinSendFile(filePath);
        }

        /// <summary>
        /// 獲取當前系統時間
        /// </summary>
        public DateTime GetCurrentTime()
        {
            DateTime currentTime = new DateTime();
            currentTime = DateTime.Now;
            return currentTime;
        }

        //關閉客戶端
        private void btnExit_Click(object sender, EventArgs e)
        {
            //Application.Exit();
        }


        /// <summary>
        /// 封裝發送訊息
        /// </summary>
        /// <param name="SReceiveUserID"></param>
        /// <param name="SMessage"></param>
        /// <returns></returns>
        public string XamarinMessageAmanager(string SReceiveUserID, string SMessage)
        {
            MessageAmanager message = new MessageAmanager() { Message = SMessage, ReceiveUserID = SReceiveUserID, SendUserID = DeviceHelp.MyUserID };
            return JsonConvert.SerializeObject(message);
        }

    }

    /// <summary>
    ///訊息管理
    /// </summary>
    public class MessageAmanager
    {
        /// <summary>
        /// 發送者ID
        /// </summary>
        public string SendUserID { get; set; }
        /// <summary>
        /// 訊息
        /// </summary>
        public string Message { get; set; }
        /// <summary>
        /// 接收者ID
        /// </summary>
        public string ReceiveUserID { get; set; }

    }

NavigationClass UI 頁面跳出工具類

 public static class NavigationClass
    {
        /// <summary>
        /// 創建副本
        /// </summary>
        public static INavigation Navigation { get; set; }
        /// <summary>
        /// 跳轉頁面
        /// </summary>
        /// <param name="obj"></param>
        public static void PushAsync(this Page obj)
        {
            Navigation.PushAsync(obj, true);
        }
        /// <summary>
        /// 關閉視窗
        /// </summary>
        /// <param name="obj"></param>
        public static void PopAsync(this Page obj)
        {
            Navigation.PopAsync(true);
        }

        public static void RemovePage(this Page obj)
        {
            Navigation.RemovePage(obj);
        }
    }

DeviceHelp 設備引數 UI委托 檔案讀寫工具類

 public class DeviceHelp
    {

        /// <summary>
        /// 客戶端唯一ID
        /// </summary>
        public static string MyUserID = Guid.NewGuid().ToString("N");
        /// <summary>
        /// 寬度
        /// </summary>
        public static double ScreenWidth { get; set; }
        /// <summary>
        /// 高度
        /// </summary>
        public static double ScreenHeight { get; set; }
        /// <summary>
        /// 密度
        /// </summary>
        public static double Density { get; set; }

        /// <summary>
        /// 背景關系物件
        /// </summary>
        public static Context Context { get; set; }

        /// <summary>
        /// Sockect 實體化物件
        /// </summary>
        public static XamarinSockectClient xamarinSockectClient { get; set; }

        /// <summary>
        /// UI委托
        /// </summary>
        public static DevDelegateUpdateUi devDelegateUpdateUi { get; set; }
        /// <summary>
        /// 訊息串列
        /// </summary>
        public static DevDelegateMessagesList devDelegateMessagesList { get; set; }

        /// <summary>
        /// 用戶名
        /// </summary>
        public static string MyUserName { get; set; }
        /// <summary>
        /// 更新標題
        /// </summary>
        public static DevDelegateTitle devDelegateTitle { get; set; }

        //var width = Resources.DisplayMetrics.WidthPixels;

        //var height = Resources.DisplayMetrics.HeightPixels;

        //var density = Resources.DisplayMetrics.Density; //


        public void SaveImage(string filepath)
        {

            var imageData = System.IO.File.ReadAllBytes(filepath);
            var dir = Android.OS.Environment.GetExternalStoragePublicDirectory(
            Android.OS.Environment.DirectoryDcim);
            var pictures = dir.AbsolutePath;
            var filename = System.DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".jpg";
            var newFilepath = System.IO.Path.Combine(pictures, filename);

            System.IO.File.WriteAllBytes(newFilepath, imageData);
            //mediascan adds the saved image into the gallery
            var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
            mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(newFilepath)));
            DevHelp.DeviceHelp.Context.SendBroadcast(mediaScanIntent);
        }

        /// <summary>
        /// 保存檔案
        /// </summary>
        /// <param name="filepath"></param>
        /// <param name="Data"></param>
        public static void SaveFile(string filepath, byte[] Data)
        {

            // var imageData = System.IO.File.ReadAllBytes(filepath);
            var dir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDcim);
            var pictures = dir.AbsolutePath;
            //  var filename = System.DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".jpg";
            var newFilepath = System.IO.Path.Combine(pictures, filepath);

            System.IO.File.WriteAllBytes(newFilepath, Data);
            //mediascan adds the saved image into the gallery
            var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
            mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(newFilepath)));
            DevHelp.DeviceHelp.Context.SendBroadcast(mediaScanIntent);
        }


        /// <summary>
        /// 讀取指定檔案
        /// </summary>
        /// <param name="filepath"></param>
        /// <returns></returns>
        public static byte[] ReadFile(string filepath)
        {
            try
            {
                var Data = System.IO.File.ReadAllBytes(filepath);
                return Data;
            }
            catch (Exception ex)
            {
                return null;
            }

        }
    }
  
    public class DevDelegateUpdateUi
    {
        public delegate void InitUi(string message);
        public InitUi InitUI;
    }

    public class DevDelegateMessagesList
    {
        public delegate void InitUi(string message);
        public InitUi AddMsg;
    }

    public class DevDelegateTitle
    {
        public delegate void UpdateTitle(string Title);
        public UpdateTitle updateTitle;
    }

DialogsListControlRenderer 在線串列資料更新實作

IOnDialogClickListener 串列單擊事件介面

必須注冊: dialogsListAdapter.OnDialogClickListener = this;

    public class DialogsListControlRenderer : ViewRenderer<DialogsListControl, LinearLayout>, IOnDialogClickListener
    {
   public DialogsListControlRenderer(Context context) : base(context)
        {

        }

        private Com.Stfalcon.Chatkit.Dialogs.DialogsList dialogsList;

        private LinearLayout linearLayout;

        private Com.Stfalcon.Chatkit.Dialogs.DialogsListAdapter dialogsListAdapter;
        protected override void OnElementChanged(ElementChangedEventArgs<DialogsListControl> e)
        {
        
            DevDelegateUpdateUi devDelegateUpdateUi = new DevDelegateUpdateUi();
            devDelegateUpdateUi.InitUI += new DevDelegateUpdateUi.InitUi(AddItem);
            DeviceHelp.devDelegateUpdateUi = devDelegateUpdateUi;
            var x = Inflate(Context, Resource.Layout.DialogsListLayout, null);
            x.Click += DialogsListView_Click;
           

            if (linearLayout == null)
            {
                linearLayout = x as LinearLayout;
            }

            if (dialogsList == null)
            {
                var dialogsListView = linearLayout.FindViewById<Com.Stfalcon.Chatkit.Dialogs.DialogsList>(Resource.Id.dialogsList1);
               
                dialogsList = dialogsListView;
            }

            dialogsList.Click += DialogsListView_Click;

            dialogsList.LongClick += DialogsListView_Click;


            dialogsListAdapter = new Com.Stfalcon.Chatkit.Dialogs.DialogsListAdapter(new SampleImageLoader(Context));

            dialogsList.SetAdapter(dialogsListAdapter); 
            DevHelp.DeviceHelp.xamarinSockectClient.XamarinGetUserInfo();
            //JsonConvert.DeserializeObject<MessageAmanager>()

            linearLayout.Click += DialogsListView_Click;
          
            dialogsListAdapter.OnDialogClickListener = this;
            SetNativeControl(linearLayout);
        }

        public void AddItem(string message)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                string[] strUser = message.Split("#");
                dialogsListAdapter.Clear();
                foreach (var item in strUser)
                {
                    var itValue = item.Split('@');
                    SampleUser sample1 = new SampleUser();
                    sample1.Avatar = itValue[1];
                    sample1.Id = itValue[0];
                    sample1.Name = itValue[1];
                    SampleMessage message1 = new SampleMessage {Id= itValue[0],Text="您有新的訊息!!!", User= sample1 };
                    SampleDialog sample = new SampleDialog(sample1, message1) { Id= itValue[0] ,DialogName= itValue[1] };
                    dialogsListAdapter.AddItem(sample);
                }            
          
            });
        }


       ///串列單擊事件
        public void OnDialogClick(Java.Lang.Object p0)
        {
            MessagesListPage messagesListPage = new MessagesListPage();
            UserInfoHelp.SampleDialog = p0 as SampleDialog;
            messagesListPage.PushAsync();
        }
       ///串列長按事件
        public void OnDialogLongClick(Java.Lang.Object p0)
        {

        }
    }

MessagesListControlRenderer 訊息動態更新實作

IOnMessageClickListener 訊息單擊事件介面

IOnMessageLongClickListener 訊息長按事件介面

介面注冊不然不會觸發 messagesListAdapter.SetOnMessageClickListener(this);
messagesListAdapter.SetOnMessageLongClickListener(this);

//好友聊天頁面標題 方法注冊
DeviceHelp.devDelegateTitle.updateTitle(UserInfoHelp.SampleDialog.DialogName);

//好友訊息動態更新方法注冊
DevDelegateMessagesList devDelegateMessages = new DevDelegateMessagesList();
devDelegateMessages.AddMsg += new DevDelegateMessagesList.InitUi(AddFendMsg);
DeviceHelp.devDelegateMessagesList = devDelegateMessages;

 public class MessagesListControlRenderer : ViewRenderer<MessagesListControl, LinearLayout>, IOnMessageClickListener, IOnMessageLongClickListener
    {
        public MessagesListControlRenderer(Context context) : base(context)
        {
            DevHelp.DeviceHelp.Context = context;
        }

        private LinearLayout linearLayout;

        private Com.Stfalcon.Chatkit.Messages.MessagesList messagesList;

        private Com.Stfalcon.Chatkit.Messages.MessagesListAdapter messagesListAdapter;
        protected override void OnElementChanged(ElementChangedEventArgs<MessagesListControl> e)
        {
            var x = Inflate(Context, Resource.Layout.MessagesListLayout, null);
            //    MessagesListControl messagesListControl= e.NewElement;
            //    messagesListControl.AddMsg += AddMsg;

            MessageManager message = new MessageManager();
            message.AddMsg += AddMsg;
            MessageHelpObj.messageManager = message;

            DevDelegateMessagesList devDelegateMessages = new DevDelegateMessagesList();
            devDelegateMessages.AddMsg += new DevDelegateMessagesList.InitUi(AddFendMsg);
            DeviceHelp.devDelegateMessagesList = devDelegateMessages;

            if (linearLayout == null)
            {
                linearLayout = x as LinearLayout;
            }

            if (messagesList == null)
            {
                var messagesListView = linearLayout.FindViewById<Com.Stfalcon.Chatkit.Messages.MessagesList>(Resource.Id.messagesList);
                messagesList = messagesListView;
            }
            //Guid.NewGuid().ToString()


            messagesListAdapter = new Com.Stfalcon.Chatkit.Messages.MessagesListAdapter(DeviceHelp.MyUserID, new SampleImageLoader(Context));

            messagesList.SetAdapter(messagesListAdapter);         

            messagesListAdapter.SetOnMessageClickListener(this);
            messagesListAdapter.SetOnMessageLongClickListener(this);


            SetNativeControl(linearLayout);
            
            DeviceHelp.devDelegateTitle.updateTitle(UserInfoHelp.SampleDialog.DialogName);
        }

        //public string guid = Guid.NewGuid().ToString();

        public string xAvatar = "xiaoming";
        public string xName = "張三";
        /// <summary>
        /// 增加訊息
        /// </summary>
        /// <param name="message"></param>
        public void AddMsg(SampleMessageControl message)
        {
            SampleMessage sample = new SampleMessage { Text = message.Text, Id = DeviceHelp.MyUserID };
            sample.User = new SampleUser() { Id = DeviceHelp.MyUserID, Avatar = xAvatar, Name = xName };

            messagesListAdapter.AddToStart(sample, true);
        }
        /// <summary>
        /// 增加訊息
        /// </summary>
        /// <param name="message"></param>
        public void AddFendMsg(string message)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                MessageBox box = JsonConvert.DeserializeObject<MessageBox>(message);

                SampleMessage sample = new SampleMessage { Text = box.Message, Id = box.SendID };
                sample.User = new SampleUser() { Id = box.SendID, Avatar = box.Name, Name = box.Name };

                messagesListAdapter.AddToStart(sample, true);
            });
        }

        public void OnMessageClick(Java.Lang.Object p0)
        {

        }

        public void OnMessageLongClick(Java.Lang.Object p0)
        {
            p0.NotifyAll();
        }

    }

    public class MessageBox
    {
        /// <summary>
        /// 接收人
        /// </summary>
        public string RID { get; set; }

        public string Message { get; set; }

        public string Name { get; set; }
        /// <summary>
        /// 發送人
        /// </summary>
        public string SendID { get; set; }
    }

MessageInputControlRenderer 發送訊息實作

IInputListener 訊息提交 介面

//OnSubmit 發送資訊
介面注冊 messageInput.SetInputListener(this);
// 發送訊息到服務器方法實作
DevHelp.DeviceHelp.xamarinSockectClient.XamarinSend(Message);

public class MessageInputControlRenderer : ViewRenderer<MessageInputControl, LinearLayout>, IInputListener
   {
       public MessageInputControlRenderer(Context context) : base(context)
       {

       }

       private Com.Stfalcon.Chatkit.Messages.MessageInput messageInput;

       private LinearLayout linearLayout;

       protected override void OnElementChanged(ElementChangedEventArgs<MessageInputControl> e)
       {
           var x = Inflate(Context, Resource.Layout.MessageInputLayout, null);
    
       
           if (linearLayout == null)
           {
               linearLayout = x as LinearLayout;
           }

           if (messageInput == null)
           {
               var messageInputView = linearLayout.FindViewById<Com.Stfalcon.Chatkit.Messages.MessageInput>(Resource.Id.theMessageInput);
               messageInput = messageInputView;
           }
           messageInput.SetInputListener(this);
           SetNativeControl(linearLayout);
       }

     

       public bool OnSubmit(ICharSequence p0)
       {
           var msg = p0.ToString();
           SampleMessageControl sample = new SampleMessageControl { Text = msg };
           MessageHelpObj.messageManager.AddMsg(sample);
           MessageBox box = new MessageBox { RID = UserInfoHelp.SampleDialog.Id, SendID = DevHelp.DeviceHelp.MyUserID, Message = p0.ToString(), Name = DevHelp.DeviceHelp.MyUserName };
           var Sedmsg = JsonConvert.SerializeObject(box);
           string Message = "000200030006#"+ Sedmsg;
           DevHelp.DeviceHelp.xamarinSockectClient.XamarinSend(Message);


           return true; 
       }
   }

##獲取設備寬度,高度 螢屏 密度
代碼實作:

 
            var width = Resources.DisplayMetrics.WidthPixels; //高度

            var height = Resources.DisplayMetrics.HeightPixels;//寬度

            var density = Resources.DisplayMetrics.Density; //螢屏密度



            DeviceHelp.ScreenWidth = width / density; //螢屏寬度

            DeviceHelp.ScreenHeight = height / density; //螢屏高度 含24個單位的標題欄高度 通過OnSizeAllocated獲取的高度不含標題欄高度

            DeviceHelp.Density = density;

以上是代碼實作:
下面展示實際效果:

請添加圖片描述
好友串列

請添加圖片描述
好友Caozhen001 與好友Caozhen002 對話實作

請添加圖片描述
好友Caozhen002與好友Caozhen001 對話實作

這里是客戶端的實作 下期介紹 服務端的實作

本期就到這里 謝謝大家,不足之處請指點一二;

需要原始碼請假博主微信

請添加圖片描述

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/298977.html

標籤:其他

上一篇:在Vue專案中,等待所有請求(方法)完成以后執行操作

下一篇:Apple補丁解決iOS、iPadOS和macOS中的0day漏洞

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more