Android总结笔记02:仿百度贴吧楼层回复功能(含表情)

最近在一个项目中做到了表情这一块,就是一个简单的回复功能。类似于百度贴吧回复楼层的样式:废话不说先上图,有图有真相。

     

大概就是这么一个发送表情的功能,其实实现起来也不是很麻烦。下面说说具体实现。

一、布局文件:

由于此Demo中用到了百度贴吧的布局,不一一展示,只把最重要的布局展示出来,其佘的在代码中看。

1、activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@id/pb"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/backgroundcolor" >

    <FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@id/layout_reply"
        android:layout_below="@id/title" >

        <ListView
            android:id="@id/pb_list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@color/backgroundcolor"
            android:cacheColorHint="@android:color/transparent"
            android:divider="@drawable/list_divider"
            android:dividerHeight="2.0dip"
            android:fadingEdge="vertical"
            android:fadingEdgeLength="3.0dip"
            android:listSelector="@drawable/list_selector"
            android:smoothScrollbar="true" />

    </FrameLayout>

    <RelativeLayout
        android:id="@id/title"
        style="@style/title_margin"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_gravity="top"
        android:background="@drawable/title_bg" >

        <Button
            android:id="@id/button_back"
            style="@style/comm_controls"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:background="@drawable/title_back"
            android:text="返回" />

        <TextView
            android:id="@id/text_title"
            style="@style/title_info"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_gravity="center_vertical"
            android:singleLine="true" />

        <Button
            android:id="@id/button_mark"
            style="@style/comm_controls"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:background="@drawable/title_comm"
            android:paddingLeft="5.0dip"
            android:paddingRight="5.0dip"
            android:text="添加书签" />
    </RelativeLayout>

    <LinearLayout
        android:id="@id/layout_reply"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/face_view"
        android:background="@drawable/sub_pb_reply_bg"
        android:orientation="horizontal"
        android:paddingTop="2.0dip" >

        <Button
            android:id="@id/button_face"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10.0dip"
            android:layout_marginRight="6.0dip"
            android:background="@drawable/sub_pb_face" />

        <EditText
            android:id="@id/reply_content"
            android:layout_width="0.0dip"
            android:layout_height="32.0dip"
            android:layout_gravity="center_vertical"
            android:layout_weight="1.0"
            android:background="@drawable/sub_pb_input_bg"
            android:maxLength="140"
            android:paddingLeft="7.0dip"
            android:paddingRight="7.0dip"
            android:singleLine="true"
            android:textColorHint="#ffa5a6a8"
            android:textSize="14.0sp" />

        <Button
            android:id="@id/reply_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="7.0dip"
            android:layout_marginRight="7.0dip"
            android:background="@drawable/sub_pb_reply"
            android:gravity="center"
            android:paddingLeft="10.0dip"
            android:paddingRight="10.0dip"
            android:text="发帖"
            android:textColor="#ff383838"
            android:textSize="14.0sp" />
    </LinearLayout>

    <View
        android:id="@id/hold"
        android:layout_width="1.0dip"
        android:layout_height="1.0dip"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="-1.0dip" />

    <GridView
        android:layout_marginTop="2dip"
        android:id="@id/face_view"
        android:layout_width="fill_parent"
        android:layout_height="220.0dip"
        android:layout_above="@id/hold"
        android:background="@drawable/write_face_bg"
        android:columnWidth="50.0dip"
        android:fadingEdge="none"
        android:focusable="false"
        android:gravity="center"
        android:horizontalSpacing="5.0dip"
        android:numColumns="auto_fit"
        android:stretchMode="columnWidth"
        android:verticalSpacing="5.0dip"
        android:visibility="gone" />

</RelativeLayout>
对应的效果图:

2、表情条目的布局,即每一个表情图片的布局:brow_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
<ImageView
    android:id="@+id/iv_brow"
    android:layout_gravity="center"
    android:layout_width="26dip"
    android:layout_height="26dip"/>
</LinearLayout>

以上就是两个主要的布局文件,当然表情的Item条目也可以在代码中写,这就看个人习惯了。

二、代码:

1、首先我把整体思路说一下,表情功能分为本地显示和上传到服务器在页面中显示两部分。一般表情是服务器给的一个xml文件(你也可以在本地自己组织一个数据),里面有相应的表情名称和所对就的code码(也许不是这样的,大体就是这样),我们解析这个xml文件来获取其中的图片名称和code码,然后用反射把表情找出来和本地图片一一对应,而上传的时候只上传所对就的code码,服务器就会根据code码找到对应的表情图片。好了说的我都有点不清楚了,还是看代码吧。

2、包的结构:根据mvc思想我把包分成四部分,


我就用本地的一个xml文件来代替服务器返回的xml文件(当然你完全可以在本地自己组织数据)。

表情的xml文件brow.xml,我把它放在assets文件夹下

<?xml version="1.0" encoding="utf-8"?>
<brows>
	<brow>
		<code><![CDATA[[em:1:]]]></code>  -->表情code码
		<name>write_face_01</name>        -->表情名字
	</brow>
	...
	...
</brows>

(1)、把表情图片放在本地的res/drawable-hdpi目录 下

(2)、根据brow.xml的数据结构,我们定义一个bean   Simle.java用来存放code码和名字

package com.demo.domain;

/**
 * 用来封装表情的bean
 *
 */
public class Smile {
	private String code;  //表情code码
	
	private String name ;  //表情名

	public String getName() {
		return name;
	}

	
	public void setName(String name) {
		this.name = name;
	}

	
	public String getCode() {
		return code;
	}


	public void setCode(String code) {
		this.code = code;
	}
	
}

(3)、解析表情的服务类:ParserBrowXml.java

package com.demo.engine;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import com.demo.domain.Smile;
import android.util.Xml;

/**
 *解析表情的xml文件
 */
public class ParserBrowXml {
public  static List<Smile> getInfo(InputStream inputStream){
		
		XmlPullParser parser = Xml.newPullParser() ;
		int eventType = 0;
		List<Smile> smiles = null ;
		Smile smile = null ;
		try {
			parser.setInput(inputStream, "UTF-8") ;
			eventType = parser.getEventType();
			while(eventType != XmlPullParser.END_DOCUMENT){
				
				switch (eventType) {
				case XmlPullParser.START_DOCUMENT:
					
					smiles = new ArrayList<Smile>() ;
					break ;
				case XmlPullParser.START_TAG:
					if("brow".equals(parser.getName())){
						smile = new Smile() ;
						
					}else if("code".equals(parser.getName())){
						smile.setCode(parser.nextText()) ;
					}else if("name".equals(parser.getName())){
						smile.setName(parser.nextText()) ;
					}
					break ;
				case XmlPullParser.END_TAG:
					if("brow".equals(parser.getName())){
						smiles.add(smile) ;
						smile = null ;
					}
					break;
					
				default:
					break;
				}
				
				eventType = parser.next() ;
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}

		return smiles;
		}
}
(4)、通用的工具类:CommUtils.java   

package com.demo.untils;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.demo.domain.Smile;
import com.demo.simplereply.R;

import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.GridView;
import android.widget.SimpleAdapter;


/**
 *  通用的工具类
 */
public class CommonUtil {
	/**
	 * 生成表情的方法 
	 * @param context 要传入的上下文
	 * @param smiles  表情集合
	 * @param gridView 要显示器的grildView
	 * @throws Exception 异常
	 */
		public static void addexpression(Context context,List<Smile> smiles,GridView gridView,InputStream inputStream) throws Exception {

			// 通过反射把资源文件中的图片取出来放在GridView上
			ArrayList<HashMap<String, Object>> lstImageItem = new ArrayList<HashMap<String, Object>>();
			for (int i = 0; i < 50; i++) {
				Smile smile = smiles.get(i);
				if (smile != null) {
					HashMap<String, Object> map = new HashMap<String, Object>();
					Field f = (Field) R.drawable.class.getDeclaredField(smile
							.getName());
					int j = f.getInt(R.drawable.class);
					map.put("ItemImage", j);// 添加图像资源的ID
					lstImageItem.add(map);

				}
			}

			// 生成适配器的ImageItem <====> 动态数组的元素,两者一一对应
			SimpleAdapter saImageItems = new SimpleAdapter(context, lstImageItem,// 数据来源
					R.layout.brow_item,
					// 动态数组与ImageItem对应的子项
					new String[] { "ItemImage" },
					// ImageItem的XML文件里面的一个ImageView
					new int[] { R.id.iv_brow });
			gridView.setSelector(new ColorDrawable(Color.TRANSPARENT));//解决点击GridView背景变黑的情况
			gridView.setAdapter(saImageItems);
		}
		/**
		 * 隐藏软键盘的方法
		 * 
		 * @param context
		 *            要传入的上下文
		 */
		public static void hiddenSoft(Context context) {
			// 取得输入方法的服务类
			InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
			View view = ((Activity) context).getCurrentFocus();
			if (view != null) {
				imm.hideSoftInputFromWindow(view.getWindowToken(), 0);// 隐藏软键盘

			}
		}
		//快速显示键盘的方法
		public static void ShowSoftFast(Context context) {
			InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
			View view = ((Activity) context).getCurrentFocus();
			if (view != null) {
				imm.showSoftInput(view, 0); // 显示软键盘
			}
		}
		
}

(5)、主Activity界面调用    

package com.demo.simplereply;

import java.io.InputStream;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;

import com.demo.domain.Smile;
import com.demo.engine.ParserBrowXml;
import com.demo.untils.CommonUtil;

public class MainActivity extends Activity implements OnClickListener{

	private Button button_face = null ;   //表情按钮
	private GridView face_view = null ;  //存放表情的GridView
	private List<Smile> smiles = null ;  //表情集合
	private boolean isKeyBoard = false ;  //标记是否是键盘
	private EditText reply_content = null ; //文本输入框
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        button_face = (Button) this.findViewById(R.id.button_face) ;  //取得表情按钮组件
        face_view = (GridView) this.findViewById(R.id.face_view) ;    //取得放置表情的gridView组件
        face_view.setOnItemClickListener(new OnItemClickListenerImpl()); //表情添加监听事件
        
        
        button_face.setOnClickListener(this) ;
        reply_content = (EditText) this.findViewById(R.id.reply_content) ;
        reply_content.setOnTouchListener(ontouchlistener) ;  //给文本输入框添加触摸事件
        
        try {
			InputStream inputStream = this.getResources().getAssets()
					.open("brow.xml");  //取得assets中的borw.xml文件
			smiles = ParserBrowXml.getInfo(inputStream);  //解析borw.xml
			CommonUtil.addexpression(this, smiles, face_view, inputStream);// 调用生情表情的方法
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.button_face:  //点击表情按钮
			if(isKeyBoard){
				button_face.setBackgroundResource(R.drawable.sub_pb_face) ;  //键盘按钮变成表情按钮
				face_view.setVisibility(View.GONE) ;                     //表情隐藏
				CommonUtil.ShowSoftFast(this) ;                        //键盘显示出来
			}else{
				button_face.setBackgroundResource(R.drawable.sub_pb_keyboard) ;  //表情按钮变成键盘按钮
				face_view.setVisibility(View.VISIBLE) ;                     //表情显示出来
				CommonUtil.hiddenSoft(this) ;                             //键盘隐藏
			}
			isKeyBoard = !isKeyBoard ;
			break;
		default:
			break;
		}
	}
	/**
	 * 触摸事件
	 */
	private OnTouchListener ontouchlistener = new OnTouchListener() {
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			face_view.setVisibility(View.GONE) ;//表情隐藏
			button_face.setBackgroundResource(R.drawable.sub_pb_face) ;//不管是键盘还是表情都要变成表情按钮
			isKeyBoard = false ;   //让调用始终让调用表情按钮的else方法
			return false;
		}
	};
	// 点击表情的实现 类
	private class OnItemClickListenerImpl implements OnItemClickListener {
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			Smile smile = smiles.get(position);
			int cursor = reply_content.getSelectionStart();
			reply_content.getText().insert(cursor, smile.getCode() + " ");
		}
	}
}

以上就完成了一个含表情发送的回复功能。由于本人属于菜鸟级别的人,所以有什么地方不好的请自己研究再改善。

源码地址:http://download.csdn.net/detail/android0012345/5779169

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值