一个类似MIUI中原生短信编辑功能
来源:互联网 发布:苹果最新系统下载软件 编辑:程序博客网 时间:2024/06/05 15:35
首先描述下需求:
1、新增短信时,进来收件人是为空,显示一行文字(提醒)
2、从通讯录选择联系人后,回到短信编辑界面,收件栏显示一行,内容为“收件人:XXX、XXX、XXX、XXX.....”
3、当点击收件栏时,收件栏内容变化,变成可删除,最多显示四行,多余四行有上下滑动轮,不足四行,是几行显示几行
4、填写短信内容,即时计算短信条算,并有文本提示
下面是实现后效果图
下面终于到了代码实现块了,主要写一些主要用到的类,其他不太重要的就忽略写,读者自行补全。
首先是短信收件人是一个自定义的流布局,这个流布局不是本人写的,只是在上面加了些修改来满足自己的业务需求。
TagFlowLayout类
import java.util.HashSet;import java.util.Iterator;import java.util.Set;import com.zhaonongzi.wnshhseller.R;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Rect;import android.os.Bundle;import android.os.Parcelable;import android.text.TextUtils;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;/** * 自定义tag 页面的整体页面 * * 实现绑定数据,事件处理 * @author admin * */public class TagFlowLayout extends FlowLayout implementsTagAdapter.OnDataChangedListener {private TagAdapter mTagAdapter;private boolean mAutoSelectEffect = true;private int mSelectedMax = -1;// -1为不限制数量private static final String TAG = "TagFlowLayout";private MotionEvent mMotionEvent;private Set<Integer> mSelectedView = new HashSet<Integer>();public TagFlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.TagFlowLayout);mAutoSelectEffect = ta.getBoolean(R.styleable.TagFlowLayout_auto_select_effect, true);mSelectedMax = ta.getInt(R.styleable.TagFlowLayout_max_select, -1);ta.recycle();if (mAutoSelectEffect) {setClickable(true);}}public TagFlowLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public TagFlowLayout(Context context) {this(context, null);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int cCount = getChildCount();for (int i = 0; i < cCount; i++) {TagView tagView = (TagView) getChildAt(i);if (tagView.getVisibility() == View.GONE)continue;if (tagView.getTagView().getVisibility() == View.GONE) {tagView.setVisibility(View.GONE);}}super.onMeasure(widthMeasureSpec, heightMeasureSpec);}public interface OnSelectListener {void onSelected(Set<Integer> selectPosSet);}private OnSelectListener mOnSelectListener;public void setOnSelectListener(OnSelectListener onSelectListener) {mOnSelectListener = onSelectListener;if (mOnSelectListener != null)setClickable(true);}public interface OnTagClickListener {boolean onTagClick(View view, int position, FlowLayout parent);}private OnTagClickListener mOnTagClickListener;public void setOnTagClickListener(OnTagClickListener onTagClickListener) {mOnTagClickListener = onTagClickListener;if (onTagClickListener != null)setClickable(true);}public void setAdapter(TagAdapter adapter) {// if (mTagAdapter == adapter)// return;mTagAdapter = adapter;mTagAdapter.setOnDataChangedListener(this);changeAdapter();}private void changeAdapter() {removeAllViews();TagAdapter adapter = mTagAdapter;TagView tagViewContainer = null;HashSet preCheckedList = mTagAdapter.getPreCheckedList();for (int i = 0; i < adapter.getCount(); i++) {View tagView = adapter.getView(this, i, adapter.getItem(i));tagViewContainer = new TagView(getContext());// ViewGroup.MarginLayoutParams clp = (ViewGroup.MarginLayoutParams)// tagView.getLayoutParams();// ViewGroup.MarginLayoutParams lp = new// ViewGroup.MarginLayoutParams(clp);// lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;// lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;// lp.topMargin = clp.topMargin;// lp.bottomMargin = clp.bottomMargin;// lp.leftMargin = clp.leftMargin;// lp.rightMargin = clp.rightMargin;tagView.setDuplicateParentStateEnabled(true);tagViewContainer.setLayoutParams(tagView.getLayoutParams());tagViewContainer.addView(tagView);addView(tagViewContainer);if (preCheckedList.contains(i)) {tagViewContainer.setChecked(true);}}mSelectedView.addAll(preCheckedList);}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_UP) {mMotionEvent = MotionEvent.obtain(event);}return super.onTouchEvent(event);}@Overridepublic boolean performClick() {if (mMotionEvent == null)return super.performClick();int x = (int) mMotionEvent.getX();int y = (int) mMotionEvent.getY();mMotionEvent = null;TagView child = findChild(x, y);int pos = findPosByView(child);if (child != null) {doSelect(child, pos);if (mOnTagClickListener != null) {return mOnTagClickListener.onTagClick(child.getTagView(), pos,this);}}return super.performClick();}public void setMaxSelectCount(int count) {if (mSelectedView.size() > count) {Log.w(TAG, "you has already select more than " + count+ " views , so it will be clear .");mSelectedView.clear();}mSelectedMax = count;}public Set<Integer> getSelectedList() {return new HashSet<Integer>(mSelectedView);}private void doSelect(TagView child, int position) {if (mAutoSelectEffect) {if (!child.isChecked()) {// 处理max_select=1的情况if (mSelectedMax == 1 && mSelectedView.size() == 1) {Iterator<Integer> iterator = mSelectedView.iterator();Integer preIndex = iterator.next();TagView pre = (TagView) getChildAt(preIndex);pre.setChecked(false);child.setChecked(true);mSelectedView.remove(preIndex);mSelectedView.add(position);} else {if (mSelectedMax > 0&& mSelectedView.size() >= mSelectedMax)return;child.setChecked(true);mSelectedView.add(position);}} else {child.setChecked(false);mSelectedView.remove(position);}if (mOnSelectListener != null) {mOnSelectListener.onSelected(new HashSet<Integer>(mSelectedView));}}}private static final String KEY_CHOOSE_POS = "key_choose_pos";private static final String KEY_DEFAULT = "key_default";@Overrideprotected Parcelable onSaveInstanceState() {Bundle bundle = new Bundle();bundle.putParcelable(KEY_DEFAULT, super.onSaveInstanceState());String selectPos = "";if (mSelectedView.size() > 0) {for (int key : mSelectedView) {selectPos += key + "|";}selectPos = selectPos.substring(0, selectPos.length() - 1);}bundle.putString(KEY_CHOOSE_POS, selectPos);return bundle;}@Overrideprotected void onRestoreInstanceState(Parcelable state) {if (state instanceof Bundle) {Bundle bundle = (Bundle) state;String mSelectPos = bundle.getString(KEY_CHOOSE_POS);if (!TextUtils.isEmpty(mSelectPos)) {String[] split = mSelectPos.split("\\|");for (String pos : split) {int index = Integer.parseInt(pos);mSelectedView.add(index);TagView tagView = (TagView) getChildAt(index);tagView.setChecked(true);}}super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT));return;}super.onRestoreInstanceState(state);}private int findPosByView(View child) {final int cCount = getChildCount();for (int i = 0; i < cCount; i++) {View v = getChildAt(i);if (v == child)return i;}return -1;}private TagView findChild(int x, int y) {final int cCount = getChildCount();for (int i = 0; i < cCount; i++) {TagView v = (TagView) getChildAt(i);if (v.getVisibility() == View.GONE)continue;Rect outRect = new Rect();v.getHitRect(outRect);if (outRect.contains(x, y)) {return v;}}return null;}@Overridepublic void onChanged() {changeAdapter();}}FlowLayout类
import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;import com.zhaonongzi.wnshhseller.activity.customer.AddMessageActivity;import com.zhaonongzi.wnshhseller.utils.GlobalMemoryCache;/** * Tag 页面布局基类 主要实现测量子view,绘制view * * @author admin * */public class FlowLayout extends ViewGroup {protected List<List<View>> mAllViews = new ArrayList<List<View>>();protected List<Integer> mLineHeight = new ArrayList<Integer>();private int lines, counts, lastItem;// 限制显示多少行private boolean isShow;// 是否需要在最后显示省略号private LastListerInterface lastListerInterface = null;private int ihegth;public FlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public FlowLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public FlowLayout(Context context) {this(context, null);}public void setLines(int line) {this.lines = line;}public int getLastItem() {Log.e("lastItem", lastItem + "");return lastItem;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);int modeWidth = MeasureSpec.getMode(widthMeasureSpec);int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);int modeHeight = MeasureSpec.getMode(heightMeasureSpec);// wrap_contentint width = 0;int height = 0;int lineWidth = 0;int lineHeight = 0;int childHeight1 = 0;int cCount = getChildCount();for (int i = 0; i < cCount; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {if (i == cCount - 1) {width = Math.max(lineWidth, width);height += lineHeight;}continue;}measureChild(child, widthMeasureSpec, heightMeasureSpec);MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;int childHeight = child.getMeasuredHeight() + lp.topMargin+ lp.bottomMargin;childHeight1 = childHeight;if (lineWidth + childWidth > sizeWidth - getPaddingLeft()- getPaddingRight()) {width = Math.max(width, lineWidth);lineWidth = childWidth;height += lineHeight;lineHeight = childHeight;} else {lineWidth += childWidth;lineHeight = Math.max(lineHeight, childHeight);}if (i == cCount - 1) {width = Math.max(lineWidth, width);height += lineHeight;}if (lastItem == 0 && height == (3 * childHeight)) {lastItem = i - 1;if (lastItem > 0 && null != lastListerInterface) {lastListerInterface.getLastItem(lastItem);}}// Log.e("lastItem", lastItem + "");}height = (height <= (lines * childHeight1)) ? height: (lines * childHeight1);ihegth = height;AddMessageActivity.iheight = childHeight1;setMeasuredDimension(//modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width+ getPaddingLeft() + getPaddingRight(),modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height+ getPaddingTop() + getPaddingBottom()//);}public int getHeigth() {return ihegth;}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mAllViews.clear();mLineHeight.clear();int width = getWidth();int lineWidth = 0;int lineHeight = 0;List<View> lineViews = new ArrayList<View>();int cCount = getChildCount();for (int i = 0; i < cCount; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE)continue;MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width- getPaddingLeft() - getPaddingRight()) {if (mAllViews.size() < lines) {mLineHeight.add(lineHeight);mAllViews.add(lineViews);lineWidth = 0;lineHeight = childHeight + lp.topMargin + lp.bottomMargin;lineViews = new ArrayList<View>();}}lineWidth += childWidth + lp.leftMargin + lp.rightMargin;lineHeight = Math.max(lineHeight, childHeight + lp.topMargin+ lp.bottomMargin);lineViews.add(child);}mLineHeight.add(lineHeight);mAllViews.add(lineViews);int left = getPaddingLeft();int top = getPaddingTop();int lineNum = mAllViews.size();AddMessageActivity.ilines = lineNum;if (lines > 0) {lineNum = lineNum > lines ? lines : lineNum;}for (int i = 0; i < lineNum; i++) {lineViews = mAllViews.get(i);lineHeight = mLineHeight.get(i);for (int j = 0; j < lineViews.size(); j++) {View child = lineViews.get(j);if (child.getVisibility() == View.GONE) {continue;}MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int lc = left + lp.leftMargin;int tc = top + lp.topMargin;int rc = lc + child.getMeasuredWidth();int bc = tc + child.getMeasuredHeight();child.layout(lc, tc, rc, bc);left += child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;}left = getPaddingLeft();top += lineHeight;}if ((boolean) GlobalMemoryCache.getInstance().get("addMessage")) {AddMessageActivity.tfl_add_message_labellay.setVisibility(View.GONE);AddMessageActivity.scr_add_message_labellay.setVisibility(View.GONE);}}@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(), attrs);}@Overrideprotected LayoutParams generateDefaultLayoutParams() {return new MarginLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);}@Overrideprotected LayoutParams generateLayoutParams(LayoutParams p) {return new MarginLayoutParams(p);}public interface LastListerInterface {public void getLastItem(int lastItem);}public void setLastListener(LastListerInterface lastListerInterface) {this.lastListerInterface = lastListerInterface;}}
TagAdapter类
import java.util.ArrayList;import java.util.Arrays;import java.util.HashSet;import java.util.List;import android.view.View;/** * tag 布局适配器 * @author admin * * @param <T> */public abstract class TagAdapter<T>{ private List<T> mTagDatas; private OnDataChangedListener mOnDataChangedListener; private HashSet<Integer> mCheckedPosList = new HashSet<Integer>(); public TagAdapter(List<T> datas) { mTagDatas = datas; } public TagAdapter(T[] datas) { mTagDatas = new ArrayList<T>(Arrays.asList(datas)); }static interface OnDataChangedListener { void onChanged(); } void setOnDataChangedListener(OnDataChangedListener listener) { mOnDataChangedListener = listener; } public void setSelectedList(int... pos) { for (int i = 0; i < pos.length; i++) mCheckedPosList.add(pos[i]); notifyDataChanged(); } HashSet<Integer> getPreCheckedList() { return mCheckedPosList; } public int getCount() { return mTagDatas == null ? 0 : mTagDatas.size(); } public void notifyDataChanged() { mOnDataChangedListener.onChanged(); } public T getItem(int position) { return mTagDatas.get(position); } public abstract View getView(FlowLayout parent, int position, T t);}TagView类
import android.content.Context;import android.view.View;import android.widget.Checkable;import android.widget.FrameLayout;/** * 单个Tag 的自定义布局 * * @author admin * */public class TagView extends FrameLayout implements Checkable{ private boolean isChecked; private static final int[] CHECK_STATE = new int[]{android.R.attr.state_checked}; public TagView(Context context) { super(context); } public View getTagView() { return getChildAt(0); } @Override public int[] onCreateDrawableState(int extraSpace) { int[] states = super.onCreateDrawableState(extraSpace + 1); if (isChecked()) { mergeDrawableStates(states, CHECK_STATE); } return states; } /** * Change the checked state of the view * * @param checked The new checked state */ @Override public void setChecked(boolean checked) { if (this.isChecked != checked) { this.isChecked = checked; refreshDrawableState(); } } /** * @return The current checked state of the view */ @Override public boolean isChecked() { return isChecked; } /** * Change the checked state of the view to the inverse of its current state */ @Override public void toggle() { setChecked(!isChecked); }}
下面给出短信编辑的布局xml文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tag="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#f5f5f5" android:focusable="true" android:focusableInTouchMode="true" android:orientation="vertical" > <com.zhaonongzi.wnshhseller.view.TopBar android:id="@+id/message_mass_top" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center|top" /> <LinearLayout android:id="@+id/linear_edit_message_add_receiver" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/message_mass_top" android:orientation="horizontal" > <TextView android:id="@+id/txt_add_message_customer_declare" android:layout_width="wrap_content" android:layout_height="45dp" android:gravity="center" android:paddingLeft="15dp" android:text="收信人" android:textColor="@color/black" android:visibility="gone" /> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" > <TextView android:id="@+id/txt_add_message_add_customer_btn" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="left|center" android:paddingLeft="15dp" android:singleLine="true" android:text="点击添加收信客户" android:textColor="@color/gray" /> <ScrollView android:id="@+id/scr_add_message_labellay" android:layout_width="fill_parent" android:layout_height="90dp" android:visibility="gone" > <com.zhaonongzi.wnshhseller.view.flowlayout.TagFlowLayout android:id="@+id/tfl_add_message_labellay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/ac_include" android:layout_marginTop="4dp" android:layout_weight="1" android:paddingLeft="10dp" android:paddingRight="10dp" android:visibility="gone" tag:max_select="-1" /> </ScrollView> </FrameLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:paddingLeft="10dp" android:paddingRight="15dp" android:layout_gravity="center" android:paddingTop="5dp" android:paddingBottom="5dp"> <ImageView android:id="@+id/img_add_message_add_customer" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="center" android:src="@drawable/username" /> <TextView android:id="@+id/txt_add_message_customer_counts" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@color/black" android:text="0" /> </LinearLayout> </LinearLayout> <View android:id="@+id/line_1" android:layout_width="fill_parent" android:layout_height="1dp" android:layout_below="@+id/linear_edit_message_add_receiver" android:layout_marginBottom="2dp" android:layout_marginTop="2dp" android:background="#A0A0A0" /> <EditText android:id="@+id/edittext_add_message_add_content" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@+id/line_1" android:background="@drawable/select_white_bg" android:minHeight="80dp" android:padding="15dp" android:maxLength="650" android:scrollbars="vertical" android:maxHeight="200dp" android:textColor="@color/black" /> <TextView android:id="@+id/txt_add_message_add_content_num" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/edittext_add_message_add_content" android:layout_toLeftOf="@+id/txt_add_message_add_content_word" android:paddingTop="10dp" android:text="0" android:textColor="@color/orange_title" /> <TextView android:id="@+id/txt_add_message_add_content_word" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_below="@+id/edittext_add_message_add_content" android:paddingRight="15dp" android:paddingTop="10dp" android:text="" android:textColor="@color/gray" /></RelativeLayout>实例化一个收件人adapter
adapter = new TagAdapter<String>(meBean.getReceiver()) {final LayoutInflater mInflater = LayoutInflater.from(AddMessageActivity.this);@SuppressLint("NewApi")@Overridepublic View getView(FlowLayout parent, final int position,final String s) {final TextView tv = (TextView) mInflater.inflate(R.layout.item_label_tv_medium,tfl_add_message_labellay, false);SpannableStringBuilder sp1 = new SpannableStringBuilder(s);// 姓名SpannableStringBuilder sp2 = new SpannableStringBuilder("x");// 删除sp1.setSpan(new ForegroundColorSpan(Color.rgb(102, 102, 102)), 0, s.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);sp2.setSpan(new ForegroundColorSpan(Color.rgb(255, 0, 0)),0, "X".length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);SpannableStringBuilder sp = new SpannableStringBuilder();//sp.append(sp1).append(sp2);if (position == 0) {tv.setText(s);tv.setTextColor(android.graphics.Color.parseColor("#666666"));} else {tv.setText(sp);tv.setTextSize(16);tv.setBackgroundResource(R.drawable.selector_contacts_gray_btn);}tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 跳页面带值if (position != 0) {meBean.getReceiver().remove(position);handler.sendEmptyMessage(1);}}});return tv;}};
计算短信条数方法:
/** * 计算短信内容条算 * * @param wordNum * @return */public int getSMSCounts(int wordNum) {int counts;if (wordNum <= 63)counts = 1;else if (wordNum <= 127)counts = 2;else {counts = (wordNum - 127) % 67 == 0 ? ((wordNum - 127) / 67 + 2): ((wordNum + 7) / 67 + 1);}return counts;}
监听编辑文本框来提示短信条数和字数:
edittext_edit_message_add_content.addTextChangedListener(new TextWatcher() {@Overridepublic void onTextChanged(CharSequence s, int start,int before, int count) {// TODO Auto-generated method stub}@Overridepublic void beforeTextChanged(CharSequence s, int start,int count, int after) {}@Overridepublic void afterTextChanged(Editable s) {if (getSMSCounts(edittext_edit_message_add_content.getText().toString().trim().length()) == 1) {int c = 63 - edittext_edit_message_add_content.getText().toString().trim().length();txt_add_message_add_content_num.setText(c + "");txt_add_message_add_content_word.setText("");} else if (getSMSCounts(edittext_edit_message_add_content.getText().toString().trim().length()) == 2) {int c = 127 - edittext_edit_message_add_content.getText().toString().trim().length();txt_add_message_add_content_num.setText(c + "");txt_add_message_add_content_word.setText("(2)");} else if (getSMSCounts(edittext_edit_message_add_content.getText().toString().trim().length()) > 2) {int c = getSMSCounts(edittext_edit_message_add_content.getText().toString().trim().length())* 67- 7- edittext_edit_message_add_content.getText().toString().trim().length();txt_add_message_add_content_num.setText(c + "");txt_add_message_add_content_word.setText("("+ getSMSCounts(edittext_edit_message_add_content.getText().toString().trim().length()) + ")");}}});
接收删除后的handler处理:
private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {if (msg.what == 1) {tfl_add_message_labellay.onChanged();txt_add_message_customer_counts.setText((meBean.getReceiver().size() - 1) + "");}};};
上面已经把关键的代码都贴出来了,其实最重要的 地方是按流布局去显示收件人,原生的是没有限制显示行数,也没有处理多行后的滑动轮,头疼的地方是去计算显示高度并动态设置scrollview的高地。坑都已经踩过了,但是这个代码的效率不是很高,有待继续完善,或者有什么好的建议也可以给我提。
1 0
- 一个类似MIUI中原生短信编辑功能
- 将原生的Launcher修改成类似MiUI的Launcher
- 原生JS中有着类似功能的方法性能对比
- 原生短信添加一个自动亮屏的功能(不包括彩信)
- 使用Repeater实现类似GridView编辑功能
- C# DataGridView中实现类似ComboBox可编辑的下拉框功能
- C# DataGridView中实现类似ComboBox可编辑的下拉框功能
- 类似短信中添加人的layout
- XCode中类似reveal功能
- Android 实现任务栏出现类似短信的提示功能
- 可编辑div的使用,实现类似textarea功能
- awk之原文编辑(类似 sed -i 功能)
- 实现一个功能类似Any的类
- 在Git中如何使用类似SVN中的revert功能恢复一个changed file
- 用C语言写一个数组,实现类似JAVA语言中ArrayList的功能
- miui 系统组件 功能提示
- 在QT4中使用类似QVBox类似功能
- 在QT4中使用类似QVBox类似功能
- 科比告别赛致大众,尤其深刻意向那一句“man”,全场沸腾
- 自定义View实现图片缩放
- OpenKM开发环境搭建
- 新建maven时报错-----------解决:换一个工作空间,或者将工作空间的pom.xm删除
- MATLAB im2colstep
- 一个类似MIUI中原生短信编辑功能
- android 布局属性大全
- C#模拟http 发送post请求 模拟登录
- 正则表达 基础学习
- HDU 1021 Fibonacci Again
- tomcat监听器ServletContextListener加载web应用数据
- BZOJ1861——book
- java程序中对堆栈的理解
- 发短信/邮件/打电话