zoukankan      html  css  js  c++  java
  • Android开发系列(十六) QQ聊天界面完整版——整合气泡、表情、历史表情等功能

     QQ项目最新Demo:http://vdisk.weibo.com/s/uu2pYkVAKnYWh

     这是寒假最后一弹,首先我应该对持续关注我博客的朋友们表示歉意,因为我只是想完成这个项目,由于其中涉及了很多的知识点,我实在每一办法一一讲出,只能提一些主要的东西,其余的一些细节还希望大家参考我的代码。这些代码实际上也为我以后再次着手学习Android开发打好基础。本节Demo下载链接会尽快上传~

      正如之前所料,果然没有把QQ项目彻底完成。总体上看,总共做出了三个主要的界面,接下来的工作就是进行网络通信等相关的配置了,本节的主要内容是彻底完成QQ聊天界面,众所周知QQ聊天的表情界面有一个“历史表情”的功能,如下图所示:

    【QQ官方效果】

    要实现这一效果,就需要把ViewFlipper放进一个TabView中,PS:如果大家不想用TabView,可以考虑使用Fragment,但由于我对这一控件掌握的并不熟练,所以暂时仍用TabHost+TabView实现,我的效果图如下:

     

    这意味着需要创建两个Activity,分别显示系统原有的表情和“历史表情”,实际上这两个Activity是类似的,只不过表情的列数不一样而已,下面就是其中一个Activity的代码:

    package com.example.android_qqfix;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    
    import com.dragon.face.FaceHistoryData;
    
    
    
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Color;
    import android.graphics.drawable.ColorDrawable;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.view.animation.AnimationUtils;
    import android.widget.BaseAdapter;
    import android.widget.GridView;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ViewFlipper;
    
    public class MyFaceActivity extends Activity{
    
        int[] faceId={R.drawable.f_static_000,R.drawable.f_static_001,R.drawable.f_static_002,R.drawable.f_static_003
                ,R.drawable.f_static_004,R.drawable.f_static_005,R.drawable.f_static_006,R.drawable.f_static_009,R.drawable.f_static_010,R.drawable.f_static_011
                ,R.drawable.f_static_012,R.drawable.f_static_013,R.drawable.f_static_014,R.drawable.f_static_015,R.drawable.f_static_017,R.drawable.f_static_018};
        String[] faceName={"\呲牙","\淘气","\流汗","\偷笑","\再见","\敲打","\擦汗","\流泪","\掉泪","\小声","\炫酷","\发狂"
                 ,"\委屈","\便便","\菜刀","\微笑","\色色","\害羞"};
        
        protected ViewFlipper viewFlipper=null;
        protected LinearLayout pagePoint=null;
        ArrayList<ArrayList<HashMap<String,Object>>> listGrid=null;
        ArrayList<ImageView> pointList=null;
        public static MyFaceHandler faceHandler=null;
        
        public static final int ActivityId=1;
        
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.myface_layout);
            
            System.out.println("MyFace is onCreate");
            
            faceHandler=new MyFaceHandler(Looper.myLooper());
            
            viewFlipper=(ViewFlipper)findViewById(R.id.faceFlipper);
            pagePoint=(LinearLayout)findViewById(R.id.pagePoint);
            listGrid=new ArrayList<ArrayList<HashMap<String,Object>>>();
            pointList=new ArrayList<ImageView>();
            
            
            addFaceData();
            addGridView();
            setPointEffect(0);
        }
        
        public class MyFaceHandler extends Handler{
    
            public MyFaceHandler(Looper looper){
                super(looper);
            }
            
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                switch(msg.what){
                
                case ChatActivity.ActivityID:
                    if(msg.obj.toString().equals("collapse")){   //关闭表情
                        
                        if(ChatActivity.currentTabTag.equals("face"))
                            viewFlipper.setDisplayedChild(0);
                        setPointEffect(0);
                        
                    }
                    
                    
                }
                
                
            }
            
        }
        
        private void addFaceData(){
            if(listGrid!=null)
                listGrid.clear();                //首先将先前的数据清空
            ArrayList<HashMap<String,Object>> list=null;
            for(int i=0; i<faceId.length; i++){
                if(i%14==0){
                    list=new ArrayList<HashMap<String,Object>>();
                    listGrid.add(list);
                }  
                HashMap<String,Object> map=new HashMap<String,Object>();
                map.put("image", faceId[i]);
                map.put("faceName", faceName[i]);
                
                /**
                 * 这里把表情对应的名字也添加进数据对象中,便于在点击时获得表情对应的名称
                 */
                listGrid.get(i/14).add(map);        
            }
            System.out.println("listGrid size is "+listGrid.size());
        }
        
        private void addGridView(){
            if(viewFlipper!=null){
                viewFlipper.removeAllViews();
                pagePoint.removeAllViews();
                pointList.clear();               //更新前首先清除原有的所有数据
            }
            for(int i=0; i< listGrid.size();i++){
                View view=LayoutInflater.from(this).inflate(R.layout.view_item, null);
                GridView gv=(GridView)view.findViewById(R.id.myGridView);
                gv.setNumColumns(5);
                gv.setSelector(new ColorDrawable(Color.TRANSPARENT));
                MyGridAdapter adapter=new MyGridAdapter(this, listGrid.get(i), R.layout.chat_grid_item, new String[]{"image"}, new int[]{R.id.gridImage});
                gv.setAdapter(adapter);
                gv.setOnTouchListener(new MyTouchListener(viewFlipper));
                viewFlipper.addView(view);
            //    ImageView image=new ImageView(this);
            //    ImageView image=(ImageView)LayoutInflater.from(this).inflate(R.layout.image_point_layout, null);
                /**
                 * 这里不喜欢用Java代码设置Image的边框大小等,所以单独配置了一个Imageview的布局文件
                 */
                View pointView=LayoutInflater.from(this).inflate(R.layout.point_image_layout, null);
                ImageView image=(ImageView)pointView.findViewById(R.id.pointImageView);
                image.setBackgroundResource(R.drawable.qian_point);
                pagePoint.addView(pointView);   
                /**
                 * 这里验证了LinearLayout属于ViewGroup类型,可以采用addView 动态添加view
                 */
                
                pointList.add(image);
                /**
                 * 将image放入pointList,便于修改点的颜色
                 */
            }
        
        }
        
        
        /**
         * 设置游标(小点)的显示效果
         * @param darkPointNum    
         */
        private void setPointEffect(int darkPointNum){
            for(int i=0; i<pointList.size(); i++){
                pointList.get(i).setBackgroundResource(R.drawable.qian_point);
            }
            if(pointList.size()>0)
                pointList.get(darkPointNum).setBackgroundResource(R.drawable.shen_point);
        }
        private boolean moveable=true;
        private float startX=0;
        
        /**
         * 用到的方法 viewFlipper.getDisplayedChild()  获得当前显示的ChildView的索引
         * @author Administrator
         *
         */
        class MyTouchListener implements OnTouchListener{
    
            ViewFlipper viewFlipper=null;
            
            
            public MyTouchListener(ViewFlipper viewFlipper) {
                super();
                this.viewFlipper = viewFlipper;
            }
    
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch(event.getAction()){
                case MotionEvent.ACTION_DOWN:startX=event.getX(); moveable=true; break;
                case MotionEvent.ACTION_MOVE:
                    if(moveable){
                        if(event.getX()-startX>40){
                            moveable=false;
                            int childIndex=viewFlipper.getDisplayedChild();
                            /**
                             * 这里的这个if检测是防止表情列表循环滑动
                             */
                            if(childIndex>0){
                                viewFlipper.setInAnimation(AnimationUtils.loadAnimation(MyFaceActivity.this, R.anim.left_in));
                                viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(MyFaceActivity.this, R.anim.right_out));                        
                                viewFlipper.showPrevious();
                                setPointEffect(childIndex-1);
                            }
                        }
                        else if(event.getX()-startX<-40){
                            moveable=false;
                            int childIndex=viewFlipper.getDisplayedChild();
                            /**
                             * 这里的这个if检测是防止表情列表循环滑动
                             */
                            if(childIndex<listGrid.size()-1){
                                viewFlipper.setInAnimation(AnimationUtils.loadAnimation(MyFaceActivity.this, R.anim.right_in));
                                viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(MyFaceActivity.this, R.anim.left_out));
                                viewFlipper.showNext();
                                setPointEffect(childIndex+1);
                            }
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:moveable=true;break;
                default:break;
                }
                
                return false;
            }
            
        }
        
        
        /**
         * GridViewAdapter
         * @param textView
         * @param text
         */
        
        class MyGridAdapter extends BaseAdapter{
    
            Context context;
            ArrayList<HashMap<String,Object>> list;
            int layout;
            String[] from;
            int[] to;
            
            
            public MyGridAdapter(Context context,
                    ArrayList<HashMap<String, Object>> list, int layout,
                    String[] from, int[] to) {
                super();
                this.context = context;
                this.list = list;
                this.layout = layout;
                this.from = from;
                this.to = to;
            }
    
            @Override
            public int getCount() {
                // TODO Auto-generated method stub
                return list.size();
            }
    
            @Override
            public Object getItem(int position) {
                // TODO Auto-generated method stub
                return null;
            }  
    
            @Override
            public long getItemId(int position) {
                // TODO Auto-generated method stub
                return position;
            }
    
            class ViewHolder{
                ImageView image=null;
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                // TODO Auto-generated method stub
                ViewHolder holder=null;
                if(convertView==null){
                    convertView=LayoutInflater.from(context).inflate(layout, null);
                    holder=new ViewHolder();
                    holder.image=(ImageView)convertView.findViewById(to[0]);
                    convertView.setTag(holder);
                }
                else{
                    holder=(ViewHolder)convertView.getTag();
                }
                holder.image.setImageResource((Integer)list.get(position).get(from[0]));
                class MyGridImageClickListener implements OnClickListener{
    
                    int position;
                    
                    public MyGridImageClickListener(int position) {
                        super();
                        this.position = position;
                    }
    
    
                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        //editText.append((String)list.get(position).get("faceName"));
                        Message msg=new Message();
                        msg.what=MyFaceActivity.ActivityId;
                        msg.arg1=0;
                        msg.obj=(String)list.get(position).get("faceName");
                        ChatActivity.chatHandler.sendMessage(msg);
                        //一个消息不能被多个Handler使用!!!
                        
                        if(FaceHistoryData.faceHistoryList==null){
                            FaceHistoryData.faceHistoryList=new ArrayList<HashMap<String,Object>>();
                        }
                        
                        int index=0;
                        int curFaceId=(Integer)list.get(position).get("image");
                        for(index=0; index<FaceHistoryData.faceHistoryList.size(); index++){
                            if((Integer)FaceHistoryData.faceHistoryList.get(index).get("faceId")==curFaceId){
                                break;
                            }
                        }
                        if(index>=FaceHistoryData.faceHistoryList.size()){
                            HashMap<String,Object> map=new HashMap<String,Object>();
                            map.put("faceId", (Integer)list.get(position).get("image"));
                            map.put("faceName", (String)list.get(position).get("faceName"));
                            FaceHistoryData.faceHistoryList.add(0, map);     //前插入
                            int curSize=FaceHistoryData.faceHistoryList.size();  //控制长度
                            if(curSize>36){
                                FaceHistoryData.faceHistoryList.remove(curSize-1);
                            }
                        }
                            
                        
                    }
                    
                }
                //这里创建了一个方法内部类
                holder.image.setOnClickListener(new MyGridImageClickListener(position));
                        
                return convertView;
            }
            
        }
    
        
    
        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            addFaceData();
            addGridView();
            setPointEffect(0);
            super.onResume();
        }
    
        
        
        
    
    }


    对应的布局文件

    <?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="wrap_content" >
        
            <ViewFlipper 
                android:id="@+id/faceFlipper"
                android:layout_width="match_parent"
                android:layout_height="130dip"
                android:background="#d0d3d5"
                >
            </ViewFlipper>
        
            <LinearLayout 
                android:id="@+id/pagePoint"
                android:layout_width="match_parent"
                android:layout_height="20dip"
                android:layout_below="@id/faceFlipper"
                android:background="#d0d3d5"
                android:gravity="center"
                android:orientation="horizontal">
                
            </LinearLayout>
    
    </RelativeLayout>


    另外一个是历史表情 FaceHistoryActivity,其实和MyFaceActivity很像

    package com.example.android_qqfix;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Color;
    import android.graphics.drawable.ColorDrawable;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.view.animation.AnimationUtils;
    import android.widget.BaseAdapter;
    import android.widget.GridView;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ViewFlipper;
    
    import com.dragon.face.FaceHistoryData;
    import com.example.android_qqfix.MyFaceActivity.MyFaceHandler;
    import com.example.android_qqfix.MyFaceActivity.MyGridAdapter;
    import com.example.android_qqfix.MyFaceActivity.MyTouchListener;
    import com.example.android_qqfix.MyFaceActivity.MyGridAdapter.ViewHolder;
    
    public class FaceHistoryActivity extends Activity{
    
        int[] faceId;
        String[] faceName;
        
        protected ViewFlipper viewFlipper=null;
        protected LinearLayout pagePoint=null;
        ArrayList<ArrayList<HashMap<String,Object>>> listGrid=null;
        ArrayList<ImageView> pointList=null;
        
        public static final int ActivityId=2;
        public static Handler faceHistoryHandler=null;  
    
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            setContentView(R.layout.myface_layout);
            
            
            faceHistoryHandler=new FaceHistoryHandler(Looper.myLooper());
        
            viewFlipper=(ViewFlipper)findViewById(R.id.faceFlipper);
            pagePoint=(LinearLayout)findViewById(R.id.pagePoint);
            listGrid=new ArrayList<ArrayList<HashMap<String,Object>>>();
            pointList=new ArrayList<ImageView>();
            
            viewFlipper.setOnTouchListener(new MyTouchListener(viewFlipper));
            
            parseFaceHistoryList();     //首先创建faceId faceName
            addFaceData();
            addGridView();
            setPointEffect(0);
        }  
        
        
        public class FaceHistoryHandler extends Handler{
    
            public FaceHistoryHandler(Looper looper){
                super(looper);
            }
            
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                switch(msg.what){
                
                case ChatActivity.ActivityID:
                    if(msg.obj.toString().equals("collapse")){   //关闭表情
                        
                        if(ChatActivity.currentTabTag.equals("faceHistory"))
                            viewFlipper.setDisplayedChild(0);
                        setPointEffect(0);
                        
                    }
                    
                    
                }
                
                
            }
            
        }
    
        
        
        private void parseFaceHistoryList(){
            if(FaceHistoryData.faceHistoryList==null){
                faceId=new int[0];
                faceName=new String[0];
                
                System.out.println("没装进来!!!");
            }
            else{
                faceId=new int[FaceHistoryData.faceHistoryList.size()];
                faceName=new String[FaceHistoryData.faceHistoryList.size()];
                for(int i=0; i<FaceHistoryData.faceHistoryList.size(); i++){
                    faceId[i]=(Integer)FaceHistoryData.faceHistoryList.get(i).get("faceId");
                    faceName[i]=(String)FaceHistoryData.faceHistoryList.get(i).get("faceName");
                }
            }
        }
        
        private void addFaceData(){
            ArrayList<HashMap<String,Object>> list=null;
            if(listGrid!=null)
                listGrid.clear();                //首先将先前的数据清空
            for(int i=0; i<faceId.length; i++){
                if(i%11==0){
                    list=new ArrayList<HashMap<String,Object>>();
                    listGrid.add(list);
                }  
                HashMap<String,Object> map=new HashMap<String,Object>();
                map.put("image", faceId[i]);
                map.put("faceName", faceName[i]);
                
                /**
                 * 这里把表情对应的名字也添加进数据对象中,便于在点击时获得表情对应的名称
                 */
                listGrid.get(i/11).add(map);        
            }
            System.out.println("listGrid size is "+listGrid.size());
        }
        
        private void addGridView(){
            if(viewFlipper!=null){
                viewFlipper.removeAllViews();
                pagePoint.removeAllViews();
                pointList.clear();               //更新前首先清除原有的所有数据
            }
            
            for(int i=0; i< listGrid.size();i++){
                View view=LayoutInflater.from(this).inflate(R.layout.view_item, null);
                GridView gv=(GridView)view.findViewById(R.id.myGridView);
                gv.setNumColumns(4);
                gv.setSelector(new ColorDrawable(Color.TRANSPARENT));
                MyGridAdapter adapter=new MyGridAdapter(this, listGrid.get(i), R.layout.chat_grid_item, new String[]{"image"}, new int[]{R.id.gridImage});
                gv.setAdapter(adapter);
                gv.setOnTouchListener(new MyTouchListener(viewFlipper));
                viewFlipper.addView(view);
            //    ImageView image=new ImageView(this);
            //    ImageView image=(ImageView)LayoutInflater.from(this).inflate(R.layout.image_point_layout, null);
                /**
                 * 这里不喜欢用Java代码设置Image的边框大小等,所以单独配置了一个ImageView的布局文件
                 */
                View pointView=LayoutInflater.from(this).inflate(R.layout.point_image_layout, null);
                ImageView image=(ImageView)pointView.findViewById(R.id.pointImageView);
                image.setBackgroundResource(R.drawable.qian_point);
                pagePoint.addView(pointView);   
                /**
                 * 这里验证了LinearLayout属于ViewGroup类型,可以采用addView 动态添加view
                 */
                
                pointList.add(image);
                /**
                 * 将image放入pointList,便于修改点的颜色
                 */
            }
        
        }
        
        
        /**
         * 设置游标(小点)的显示效果
         * @param darkPointNum
         */
        private void setPointEffect(int darkPointNum){
            for(int i=0; i<pointList.size(); i++){
                pointList.get(i).setBackgroundResource(R.drawable.qian_point);
            }
            if(pointList.size()>0)
                pointList.get(darkPointNum).setBackgroundResource(R.drawable.shen_point);
        }
        private boolean moveable=true;
        private float startX=0;
        
        /**
         * 用到的方法 viewFlipper.getDisplayedChild()  获得当前显示的ChildView的索引
         * @author Administrator
         *
         */
        class MyTouchListener implements OnTouchListener{
    
            ViewFlipper viewFlipper=null;
            
            
            public MyTouchListener(ViewFlipper viewFlipper) {
                super();
                this.viewFlipper = viewFlipper;
            }
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch(event.getAction()){
                case MotionEvent.ACTION_DOWN:startX=event.getX(); moveable=true; break;
                case MotionEvent.ACTION_MOVE:
                    if(moveable){
                        if(event.getX()-startX>40){
                            moveable=false;
                            int childIndex=viewFlipper.getDisplayedChild();
                            /**
                             * 这里的这个if检测是防止表情列表循环滑动
                             */
                            if(childIndex>0){
                                viewFlipper.setInAnimation(AnimationUtils.loadAnimation(FaceHistoryActivity.this, R.anim.left_in));
                                viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(FaceHistoryActivity.this, R.anim.right_out));                        
                                viewFlipper.showPrevious();
                                setPointEffect(childIndex-1);
                            }
                        }
                        else if(event.getX()-startX<-40){
                            moveable=false;
                            int childIndex=viewFlipper.getDisplayedChild();
                            /**
                             * 这里的这个if检测是防止表情列表循环滑动
                             */
                            if(childIndex<listGrid.size()-1){
                                viewFlipper.setInAnimation(AnimationUtils.loadAnimation(FaceHistoryActivity.this, R.anim.right_in));
                                viewFlipper.setOutAnimation(AnimationUtils.loadAnimation(FaceHistoryActivity.this, R.anim.left_out));
                                viewFlipper.showNext();
                                setPointEffect(childIndex+1);
                            }
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:moveable=true;break;
                default:break;
                }
                
                return false;
            }
            
        }
        
        
        /**
         * GridViewAdapter
         * @param textView
         * @param text
         */
        
        class MyGridAdapter extends BaseAdapter{
    
            Context context;
            ArrayList<HashMap<String,Object>> list;
            int layout;
            String[] from;
            int[] to;
            
            
            public MyGridAdapter(Context context,
                    ArrayList<HashMap<String, Object>> list, int layout,
                    String[] from, int[] to) {
                super();
                this.context = context;
                this.list = list;
                this.layout = layout;
                this.from = from;
                this.to = to;
            }
    
            @Override
            public int getCount() {
                // TODO Auto-generated method stub
                return list.size();
            }
    
            @Override
            public Object getItem(int position) {
                // TODO Auto-generated method stub
                return null;
            }
    
            @Override
            public long getItemId(int position) {
                // TODO Auto-generated method stub
                return position;
            }
    
            class ViewHolder{
                ImageView image=null;
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                // TODO Auto-generated method stub
                ViewHolder holder=null;
                if(convertView==null){
                    convertView=LayoutInflater.from(context).inflate(layout, null);
                    holder=new ViewHolder();
                    holder.image=(ImageView)convertView.findViewById(to[0]);
                    convertView.setTag(holder);
                }
                else{
                    holder=(ViewHolder)convertView.getTag();
                }
                holder.image.setImageResource((Integer)list.get(position).get(from[0]));
                class MyGridImageClickListener implements OnClickListener{
    
                    int position;
                    
                    public MyGridImageClickListener(int position) {
                        super();
                        this.position = position;
                    }
    
    
                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        //editText.append((String)list.get(position).get("faceName"));
                        Message msg=new Message();
                        msg.what=MyFaceActivity.ActivityId;
                        msg.arg1=0;
                        msg.obj=(String)list.get(position).get("faceName");
                        ChatActivity.chatHandler.sendMessage(msg);
                        
                    }
                    
                }
                //这里创建了一个方法内部类
                holder.image.setOnClickListener(new MyGridImageClickListener(position));
                
                
                
                return convertView;
            }
            
        }
    
    
    
    
        @Override
        protected void onPause() {
            // TODO Auto-generated method stub
            
            super.onPause();
        }
    
        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            parseFaceHistoryList();    //首先得更新数组!!
            addFaceData();
            addGridView();
            setPointEffect(0);
            super.onResume();
        }
    
    
    
    
    
        @Override
        protected void onStart() {
            // TODO Auto-generated method stub
        
            super.onStart();
        }
        
        
        
    
    }

      因为在点击表情界面的某个表情时会修改ChatActivity中EditText中的内容,所以需要为ChatActivity设置Handler,该Handler对象绑定ChatActivity的Looper,这里把Handler设置为静态公共 public static对象,以使在其他Activity中能够访问到这一个handler,具体代码实现方式可以参考 ChatActivity ,MyFaceActivity中的 Handler的相关操作。

    ChatActivity:

    package com.example.android_qqfix;
    
    import android.app.Activity;
    import android.app.TabActivity;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Color;
    import android.graphics.drawable.ColorDrawable;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.text.Spannable;
    import android.text.SpannableString;
    import android.text.SpannableStringBuilder;
    import android.text.style.ImageSpan;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.view.ViewGroup.LayoutParams;
    import android.view.animation.AnimationUtils;
    import android.view.inputmethod.InputMethodManager;
    import android.view.ViewGroup;
    import android.view.Window;
    import android.widget.*;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.TabHost.OnTabChangeListener;
    import android.widget.TabHost.TabSpec;
    
    import java.util.*;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    
    
    
    
    
    
    public class ChatActivity extends TabActivity{
    
        int[] faceId={R.drawable.f_static_000,R.drawable.f_static_001,R.drawable.f_static_002,R.drawable.f_static_003
                ,R.drawable.f_static_004,R.drawable.f_static_005,R.drawable.f_static_006,R.drawable.f_static_009,R.drawable.f_static_010,R.drawable.f_static_011
                ,R.drawable.f_static_012,R.drawable.f_static_013,R.drawable.f_static_014,R.drawable.f_static_015,R.drawable.f_static_017,R.drawable.f_static_018};
        String[] faceName={"\呲牙","\淘气","\流汗","\偷笑","\再见","\敲打","\擦汗","\流泪","\掉泪","\小声","\炫酷","\发狂"
                 ,"\委屈","\便便","\菜刀","\微笑","\色色","\害羞"};
        
        HashMap<String,Integer> faceMap=null;
        ArrayList<HashMap<String,Object>> chatList=null;
        String[] from={"image","text"};
        int[] to={R.id.chatlist_image_me,R.id.chatlist_text_me,R.id.chatlist_image_other,R.id.chatlist_text_other};
        int[] layout={R.layout.chat_listitem_me,R.layout.chat_listitem_other};
        String userQQ=null;
        /**
         * 这里两个布局文件使用了同一个id,测试一下是否管用
         * TT事实证明这回产生id的匹配异常!所以还是要分开。。
         * 
         * userQQ用于接收Intent传递的qq号,进而用来调用数据库中的相关的联系人信息,这里先不讲
         * 先暂时使用一个头像
         */
        
        public final static int OTHER=1;
        public final static int ME=0;
        public final static int ActivityID=0;
        
        
        protected ListView chatListView=null;
        protected Button chatSendButton=null;
        protected EditText editText=null;
    
        protected ImageButton chatBottomLook=null;
        protected RelativeLayout faceLayout=null;
        protected TabHost tabHost=null;
        protected TabWidget tabWidget=null;
    
       
        private boolean expanded=false;
    
        protected MyChatAdapter adapter=null;
        protected View tabFaceHistory=null,tabFace=null;
        protected ImageView tabFaceHistoryImage=null,tabFaceImage=null;
        public static Handler chatHandler=null;
        public static String currentTabTag="face";
        public TabSpec tabSpecFaceHistory,tabSpecFace;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_chat);
        
            chatHandler=new MyChatHandler(Looper.myLooper());
            
            faceMap=new HashMap<String,Integer>();    
            chatList=new ArrayList<HashMap<String,Object>>();
            
            
            
            addTextToList("不管你是谁", ME);
            addTextToList("群发的我不回
      ^_^", OTHER);
            addTextToList("哈哈哈哈", ME);
            addTextToList("新年快乐!", OTHER);
            
            chatSendButton=(Button)findViewById(R.id.chat_bottom_sendbutton);
            editText=(EditText)findViewById(R.id.chat_bottom_edittext);
            chatListView=(ListView)findViewById(R.id.chat_list);
            tabWidget=(TabWidget)findViewById(android.R.id.tabs);
            tabHost=(TabHost)findViewById(android.R.id.tabhost);
    
            
            chatBottomLook=(ImageButton)findViewById(R.id.chat_bottom_look);
            faceLayout=(RelativeLayout)findViewById(R.id.faceLayout);
    
     
            
            /**
             * 添加选项卡
             */
            tabSpecFaceHistory=tabHost.newTabSpec("faceHistory");
            tabFaceHistory=LayoutInflater.from(this).inflate(R.layout.tabwidget_image_disselected,null);
            tabFaceHistoryImage=(ImageView)tabFaceHistory.findViewById(R.id.tabImage_disselected);
            tabFaceHistoryImage.setImageResource(R.drawable.face_history_disselected);
            tabSpecFaceHistory.setIndicator(tabFaceHistory);
            Intent intent1=new Intent();
            intent1.setClass(ChatActivity.this, FaceHistoryActivity.class);
            tabSpecFaceHistory.setContent(intent1);
            tabHost.addTab(tabSpecFaceHistory);
            
            tabSpecFace=tabHost.newTabSpec("face");
            tabFace=LayoutInflater.from(this).inflate(R.layout.tabwidget_image_selected, null);
            tabFaceImage=(ImageView)tabFace.findViewById(R.id.tabImage_selected);
            tabFaceImage.setImageResource(R.drawable.face_look_selected);
            tabSpecFace.setIndicator(tabFace);
            Intent intent2=new Intent();
            intent2.setClass(ChatActivity.this, MyFaceActivity.class);
            tabSpecFace.setContent(intent2);
            tabHost.addTab(tabSpecFace);
            
            tabHost.setCurrentTabByTag("face");     
            tabHost.setOnTabChangedListener(new OnTabChangeListener() {
                
                @Override
                public void onTabChanged(String tabId) {
                    // TODO Auto-generated method stub
                //    System.out.println("current Selected Tab "+tabId);
                    currentTabTag=tabId;
        
                    
                    
                    if(tabId.equals("face")){
                        
                        
                                         
                        tabFace.setBackgroundResource(R.drawable.tabwidget_selected);
                        tabFaceImage.setImageResource(R.drawable.face_look_selected);
                        tabSpecFace.setIndicator(tabFace);
                        
                        
                        tabFaceHistory.setBackgroundResource(R.drawable.tab_widget_disselected);
                        tabFaceHistoryImage.setImageResource(R.drawable.face_history_disselected);
                        tabSpecFaceHistory.setIndicator(tabFaceHistory);
                    }
                    else if(tabId.equals("faceHistory")){
                        
                        tabFace.setBackgroundResource(R.drawable.tabwidget_disselected);
                        tabFaceImage.setImageResource(R.drawable.face_look_disselected);
                        tabSpecFace.setIndicator(tabFace);
                        
                        tabFaceHistory.setBackgroundResource(R.drawable.tabwidget_selected);
                        tabFaceHistoryImage.setImageResource(R.drawable.face_history_selected);
                        tabSpecFaceHistory.setIndicator(tabFaceHistory);
                        
                    }
                    
                    
                }
            });
            
            
            chatBottomLook.setOnClickListener(new OnClickListener(){
      
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    if(expanded){
                        setFaceLayoutExpandState(false);
                        expanded=false;
                        
                        
                        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);  
                        imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);  
    
                        /**height不设为0是因为,希望可以使再次打开时viewFlipper已经初始化为第一页 避免
                        *再次打开ViewFlipper时画面在动的结果,
                        *为了避免因为1dip的高度产生一个白缝,所以这里在ViewFlipper所在的RelativeLayout
                        *最上面添加了一个1dip高的黑色色块
                        */
                        
                        
                    }
                    else{
    
                        setFaceLayoutExpandState(true);  
                        expanded=true;
                        
    
                    }
                }
                
            });
            
            /**EditText从未获得焦点到首次获得焦点时不会调用OnClickListener方法,所以应该改成OnTouchListener
             * 从而保证点EditText第一下就能够把表情界面关闭
            editText.setOnClickListener(new OnClickListener(){
    
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    ViewGroup.LayoutParams params=viewFlipper.getLayoutParams();
                    params.height=0;
                    viewFlipper.setLayoutParams(params);
                    expanded=false;
                    System.out.println("WHYWHWYWHYW is Clicked");
                }
                
            });
            **/
            editText.setOnTouchListener(new OnTouchListener() {
                
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // TODO Auto-generated method stub
                    if(expanded){
                        
                        setFaceLayoutExpandState(false);
                        expanded=false;
                    }
                    return false;
                }
            });
            adapter=new MyChatAdapter(this,chatList,layout,from,to);            
            chatSendButton.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    String myWord=null;
                    
                    /**
                     * 这是一个发送消息的监听器,注意如果文本框中没有内容,那么getText()的返回值可能为
                     * null,这时调用toString()会有异常!所以这里必须在后面加上一个""隐式转换成String实例
                     * ,并且不能发送空消息。
                     */
                    
                    myWord=(editText.getText()+"").toString();
                    if(myWord.length()==0)
                        return;
                    editText.setText("");
                    addTextToList(myWord, ME);
                    /**
                     * 更新数据列表,并且通过setSelection方法使ListView始终滚动在最底端
                     */
                    adapter.notifyDataSetChanged();
                    chatListView.setSelection(chatList.size()-1);
                    
                } 
            });
            
            chatListView.setAdapter(adapter);
            
            chatListView.setOnItemClickListener(new OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                        long arg3) {
                    // TODO Auto-generated method stub
                    setFaceLayoutExpandState(false);
                    ((InputMethodManager)ChatActivity.this.getSystemService(INPUT_METHOD_SERVICE)).
                    hideSoftInputFromWindow(ChatActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
                    expanded=false;
                }
            });
            
            /**
             * 为表情Map添加数据
             */
            for(int i=0; i<faceId.length; i++){
                faceMap.put(faceName[i], faceId[i]);
            }
            
            
            
            
            
        }
        
        
        
        public class MyChatHandler extends Handler{
            
            public MyChatHandler(Looper looper){
                super(looper);
            }
    
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                switch(msg.what){
                case MyFaceActivity.ActivityId:
                    if(msg.arg1==0){            //添加表情字符串
                        editText.append(msg.obj.toString());
                    }
                
                }
            }
            
            
            
        }
        
        
        /**
         * 打开或者关闭软键盘,之前若打开,调用该方法后关闭;之前若关闭,调用该方法后打开
         */
        
        private void setSoftInputState(){
            ((InputMethodManager)ChatActivity.this.getSystemService(INPUT_METHOD_SERVICE)).toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
        }
        
        private void setFaceLayoutExpandState(boolean isexpand){
            if(isexpand==false){
    
                    
                ViewGroup.LayoutParams params=faceLayout.getLayoutParams();
                params.height=1;
                faceLayout.setLayoutParams(params);    
                
                chatBottomLook.setBackgroundResource(R.drawable.chat_bottom_look);
                Message msg=new Message();
                msg.what=this.ActivityID;
                msg.obj="collapse";
                if(MyFaceActivity.faceHandler!=null)
                    MyFaceActivity.faceHandler.sendMessage(msg);
                
                Message msg2=new Message();
                msg2.what=this.ActivityID;
                msg2.obj="collapse";
                if(FaceHistoryActivity.faceHistoryHandler!=null)
                    FaceHistoryActivity.faceHistoryHandler.sendMessage(msg2);
        
                chatListView.setSelection(chatList.size()-1);//使会话列表自动滑动到最低端
                
            }
            else{
                
                ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow
                (ChatActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
                ViewGroup.LayoutParams params=faceLayout.getLayoutParams();
                params.height=185;
            //    faceLayout.setLayoutParams(new RelativeLayout.LayoutParams( ));    
                RelativeLayout.LayoutParams relativeParams=new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);
                relativeParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
                faceLayout.setLayoutParams(relativeParams);
                
                
                chatBottomLook.setBackgroundResource(R.drawable.chat_bottom_keyboard);
    
            }
        }
        
        
        
        
        
        
        
        
        private void setFaceText(TextView textView,String text){
            SpannableString spanStr=parseString(text);
            textView.setText(spanStr);
        }
        
        private void setFace(SpannableStringBuilder spb, String faceName){
            Integer faceId=faceMap.get(faceName);
            if(faceId!=null){
                Bitmap bitmap=BitmapFactory.decodeResource(getResources(), faceId);
                bitmap=Bitmap.createScaledBitmap(bitmap, 30, 30, true);
                ImageSpan imageSpan=new ImageSpan(this,bitmap);
                SpannableString spanStr=new SpannableString(faceName);
                spanStr.setSpan(imageSpan, 0, faceName.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                spb.append(spanStr);    
            }
            else{
                spb.append(faceName);
            }
            
        }
        
        private SpannableString parseString(String inputStr){
            SpannableStringBuilder spb=new SpannableStringBuilder();
            Pattern mPattern= Pattern.compile("\\..");
            Matcher mMatcher=mPattern.matcher(inputStr);
            String tempStr=inputStr;
            
            while(mMatcher.find()){
                int start=mMatcher.start();
                int end=mMatcher.end();
                spb.append(tempStr.substring(0,start));
                String faceName=mMatcher.group();
                setFace(spb, faceName);
                tempStr=tempStr.substring(end, tempStr.length());
                /**
                 * 更新查找的字符串
                 */
                mMatcher.reset(tempStr);
            }
            spb.append(tempStr);
            return new SpannableString(spb);
        }
        
        
        
        protected void addTextToList(String text, int who){
            HashMap<String,Object> map=new HashMap<String,Object>();
            map.put("person",who );
            map.put("image", who==ME?R.drawable.contact_0:R.drawable.contact_1);
            map.put("text", text);
            chatList.add(map);
        }
        
        private class MyChatAdapter extends BaseAdapter{
    
            Context context=null;
            ArrayList<HashMap<String,Object>> chatList=null;
            int[] layout;
            String[] from;
            int[] to;
              
            
            
            public MyChatAdapter(Context context,
                    ArrayList<HashMap<String, Object>> chatList, int[] layout,
                    String[] from, int[] to) {
                super();
                this.context = context;
                this.chatList = chatList;
                this.layout = layout;
                this.from = from;
                this.to = to;
            }
    
            @Override
            public int getCount() {
                // TODO Auto-generated method stub
                return chatList.size();
            }
    
            @Override
            public Object getItem(int arg0) {
                // TODO Auto-generated method stub
                return null;
            }
    
            @Override
            public long getItemId(int position) {
                // TODO Auto-generated method stub
                return position;
            }
    
            class ViewHolder{
                public ImageView imageView=null;
                public TextView textView=null;
            
            }
            
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                // TODO Auto-generated method stub
                ViewHolder holder=null;   
                int who=(Integer)chatList.get(position).get("person");
     
                    convertView= LayoutInflater.from(context).inflate(
                            layout[who==ME?0:1], null);
                    holder=new ViewHolder();
                    holder.imageView=(ImageView)convertView.findViewById(to[who*2+0]);
                    holder.textView=(TextView)convertView.findViewById(to[who*2+1]);
                
                
                holder.imageView.setBackgroundResource((Integer)chatList.get(position).get(from[0]));
                setFaceText(holder.textView, chatList.get(position).get(from[1]).toString());
                return convertView;
            }
            
        }
        
        
    
    }

      此外点击Tab选项卡时所显示出的一些动画效果是我 调用了tabHost的onTabChangedListener()方法,根据选中的不同Tab,调用 TabSpec的setIndicator设置不同的布局文件,关于背景效果的设置采用的是layer-list  这一知识点我在前面讲联系人列表的界面时已经提到,这个东西确实非常非常强大!,从最终效果可以看出,用TabView也可以做出比较漂亮的界面,也没有必要因为它被谷歌弃用了就完全抛弃它,实际上在实现一些简单的tab导航页时使用tabView更加简洁。

      另外要提的一点是:上面说的历史表情是怎样实现的呢?原理很简单:创建一个ArrayList类型或者队列类型的静态对象,用户使用某个表情后,如果这个表情之前没有使用过,就把它添加进静态对象中,然后在FaceHistoryActivity中调用parseFaceHistoryList进行解析成相应的表情列表,可以参考FaceHistoryActivity中的相关代码。

    为了从这个静态对象我单独创建了一个类,实际上只有一行代码:

    public class FaceHistoryData {
        
        public static ArrayList<HashMap<String,Object>>  faceHistoryList=null;
        
    
    }


     

      最后一点是很遗憾,我并没有实现动态表情的效果,我发现这个效果所用到的技术并不是我短时间内能掌握的,还望海涵。如果我以后找到了实现动态表情的好方法,还会更新本节的博客~~

         好啦,以上就是本节的全部内容,《Android开发系列》也会暂时告一段落了。新学期开始,我要去迎接新的挑战,重启这一系列应该是这个暑假的事情了,这一段时间在Android应用的控件和UI美化上花了一些功夫,也确实感到比半年前初学安卓时有了更进一步的理解。下次我应该会把QQ项目彻底完成了,如果时间允许可能会涉及Android游戏的开发...不多说了,希望新的大家都会取得新的成绩。

  • 相关阅读:
    51nod乘积之和
    Dell服务器安装OpenManage(OMSA)
    Nginx反向代理PHP
    搭建haproxy
    108. Convert Sorted Array to Binary Search Tree
    60. Permutation Sequence
    142. Linked List Cycle II
    129. Sum Root to Leaf Numbers
    118. Pascal's Triangle
    26. Remove Duplicates from Sorted Array
  • 原文地址:https://www.cnblogs.com/carlos-vic/p/Carlos_V_Android_16.html
Copyright © 2011-2022 走看看