仿微信、QQ的@功能
来源:互联网 发布:怎么看本子知乎 编辑:程序博客网 时间:2024/05/18 17:00
仿微信、QQ的@功能
前言:前一段时间,公司有一个项目需要加入@功能,我当时也没有啥思路,然后去网上看看有没有前人写过类似的文章或者代码。然后我在这里http://download.csdn.net/detail/u011818090/8534377找到了别人写的仿微博的@功能,感觉还可以,但是和我的需求不一样,所以就自己根据需求改编了他的代码。下面就讲讲我的@功能。
首先是需求:公司项目需求的中心思想是,你在群组聊天时,@群组中的某一个人,这个人接受到@信息,会在会话列表有标红提示,其他人接收到信息就是一个普通消息。我的当时遇到的问题就是这个,该如何让被@的人接收到信息有标红提醒。还有就是有一个非常让人难受的数据文档(格式如下所示)当时有两个方案:第一,根据名字来标记;第二,根据名字和用户Id来标记。然后再分析下:第一个方案,名字没有唯一性。所以第一个方案被排除了(排除过程很痛苦,其中经历了很多艰难的想法和尝试,就是因为这个奇葩的文档数据格式);然后是第二个方案,id有唯一性并且还可以将文档中的id填上,也可以判断content字段里面的内容是@信息还是一个普通的@文本信息。但是如何实现呢?
大家都用过微信表情吧,他内部其实是一个表情对应一个特定的字符串,我就想,为什么这个不可以呢,一个名字里面包含了名字和Id。主要思路是运用正则的方式用一张图片去替代特定格式的字符串。下面上代码。
//设置@图片和文字混搭 public static CharSequence getExpressionString(Context context, String srcText,DynamicDrawableSpan drawableSpan){ SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append(srcText); //srcText是拼接好的字符串 String text = builder.toString(); Pattern pattern = Pattern.compile("\\[2f(.*?)\\]"); //这是一个约定好的正则字符串 Matcher matcher = pattern.matcher(text); String atStr,atIndex; SpannableString spannable; int index = 0; while(matcher.find()){ atIndex = matcher.group(1);//找到正则表达式中的括号()内匹配的字符串 atStr = "[2f" + atIndex + "]"; index = matcher.start(1) - 3; //得到括号内匹配的起始坐标 spannable = new SpannableString(atStr); spannable.setSpan(drawableSpan, 0, spannable.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); builder.replace(index, index + atStr.length(), spannable); } return builder; }
上面的方法是将一个原始的拼接成特定字符串的drawableSpan进行正则替换成一个名字图片。
下面是将name和Id拼成特定字符创的代码
/** * 拼接@和姓名 * @param userName * @param userId */ private void spilecName(String userName, String userId) { int currentIndex = editText.getSelectionStart(); //获得光标的起始位置 String nameStr = "[2f" + userName + "/" + userId + "]"; //通过输入的@符号进入好友列表并返回@的人,删除之前的@ editText.getText().replace(currentIndex - 1,currentIndex,""); setAtImageSpan(nameStr,userName); }
可以看到我将name和Id拼接成String nameStr = "[2f" + userName + "/" + userId + "]";
这种形式,然后用Pattern pattern = Pattern.compile("\\[2f(.*?)\\]")
进行正则表达式匹配。下面是将文字信息转成图片信息
/** * 将@的信息转化成图片 * @param nameStr * @param name */ private void setAtImageSpan(String nameStr, String name) { Editable eidit_text = editText.getEditableText(); if (null != name){ String name1 = "@" + name + " "; //后面加一个空格为了与之后拼接的文字隔开 if (null != name1 && name1.trim().length() > 0){ final Bitmap bmp = getNameBitmap(name1); DynamicDrawableSpan drawableSpan = new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) { @Override public Drawable getDrawable() { BitmapDrawable drawable = new BitmapDrawable(getResources(),bmp); drawable.setBounds(0,0, bmp.getWidth(), bmp.getHeight()); return drawable; } }; CharSequence cs = getExpressionString(AtActivity.this, nameStr, drawableSpan); builder = new SpannableStringBuilder(cs); //获取光标所在位置 currentIndex = editText.getSelectionStart(); builder.setSpan(builder,0, builder.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } if (currentIndex < 0 || currentIndex >= eidit_text.length()) { eidit_text.append(builder); } else { eidit_text.insert(currentIndex, builder); } } /** * 将文字转成图片 * @param name * @return */ private Bitmap getNameBitmap(String name) { Paint paint = new Paint(); paint.setColor(getResources().getColor(R.color.black)); paint.setAntiAlias(true); paint.setTextSize(DensityUtils.dp2px(AtActivity.this,18)); Rect rect = new Rect(); paint.getTextBounds(name,0,name.length(),rect); //获得字符串在屏幕上的长度 int width = (int) (paint.measureText(name)); final Bitmap bmp = Bitmap.createBitmap(width,rect.height() + 8, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bmp); Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); //(行高-字体高度)/2+字体高度-6 float fontTotalHeight = fontMetrics.bottom - fontMetrics.top; // canvas.drawText(name, rect.left, rect.height() - rect.bottom, paint); float offY = fontTotalHeight / 2; float newY = rect.height() / 2 + offY; canvas.drawText(name, rect.left, newY - 4, paint); return bmp; }
通过以上的处理,就能够将name和Id信息存进一张@的图片中了。接收方通过解析@信息的内容,判断该内容中是否有自己的Id,然后系统再进行相应的处理。
大致的思路就写完了,一些简单的逻辑,大家可以看我上面给的链接的代码。或者看我下面的附上的整个代码。我的代码中还加入了群员名字的搜索功能,搜索的关键字标红处理。附上代码如下:
说明:代码只是简单的写了发送方的@功能信息,并没有实际的聊天功能(聊天比较复杂)。如果各位有做即时聊天的需要@功能的,希望我这个思路能对大家有所帮助。
AtActivity代码:
package com.example.hhly_pc.enumuse;import android.content.Context;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.support.annotation.Nullable;import android.support.v4.graphics.BitmapCompat;import android.support.v7.app.AppCompatActivity;import android.text.Editable;import android.text.InputFilter;import android.text.Spannable;import android.text.SpannableString;import android.text.SpannableStringBuilder;import android.text.Spanned;import android.text.style.DynamicDrawableSpan;import android.widget.EditText;import android.widget.Toast;import com.example.hhly_pc.enumuse.adapter.AppMannager;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * Created by hhly-pc on 2017/1/21. */public class AtActivity extends AppCompatActivity { private static int a = 0; private EditText editText; private int currentIndex; private SpannableStringBuilder builder; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_at); editText = (EditText) findViewById(R.id.et_at); //文本编辑框文字筛选 editText.setFilters(new InputFilter[]{new MyInputFilter()}); } private class MyInputFilter implements InputFilter{ @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { if (source.toString().equalsIgnoreCase("@") || source.toString().equalsIgnoreCase("@")){ goAt(); } return source; } } //匹配到@字符之后进入用户选择界面 private void goAt() { startActivityForResult(new Intent(this,PersionListActivity.class),100); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 100 && resultCode == 200){ String userId = data.getStringExtra("userId"); String userName = data.getStringExtra("userName"); System.out.println("userName111 " + userName + " userId " + userId); spilecName(userName,userId); } } /** * 拼接@和姓名 * @param userName * @param userId */ private void spilecName(String userName, String userId) { int currentIndex = editText.getSelectionStart(); //获得光标的起始位置 String nameStr = "[2f" + userName + "/" + userId + "]"; //通过输入的@符号进入好友列表并返回@的人,删除之前的@ editText.getText().replace(currentIndex - 1,currentIndex,""); setAtImageSpan(nameStr,userName); } /** * 将@的信息转化成图片 * @param nameStr * @param name */ private void setAtImageSpan(String nameStr, String name) { Editable eidit_text = editText.getEditableText(); if (null != name){ String name1 = "@" + name + " "; //后面加一个空格为了与之后拼接的文字隔开 if (null != name1 && name1.trim().length() > 0){ final Bitmap bmp = getNameBitmap(name1); DynamicDrawableSpan drawableSpan = new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) { @Override public Drawable getDrawable() { BitmapDrawable drawable = new BitmapDrawable(getResources(),bmp); drawable.setBounds(0,0, bmp.getWidth(), bmp.getHeight()); return drawable; } }; CharSequence cs = getExpressionString(AtActivity.this, nameStr, drawableSpan); builder = new SpannableStringBuilder(cs); //获取光标所在位置 currentIndex = editText.getSelectionStart(); builder.setSpan(builder,0, builder.length(),Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } if (currentIndex < 0 || currentIndex >= eidit_text.length()) { eidit_text.append(builder); } else { eidit_text.insert(currentIndex, builder); } } /** * 将文字转成图片 * @param name * @return */ private Bitmap getNameBitmap(String name) { Paint paint = new Paint(); paint.setColor(getResources().getColor(R.color.black)); paint.setAntiAlias(true); paint.setTextSize(DensityUtils.dp2px(AtActivity.this,18)); Rect rect = new Rect(); paint.getTextBounds(name,0,name.length(),rect); //获得字符串在屏幕上的长度 int width = (int) (paint.measureText(name)); final Bitmap bmp = Bitmap.createBitmap(width,rect.height() + 8, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bmp); Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt(); //(行高-字体高度)/2+字体高度-6 float fontTotalHeight = fontMetrics.bottom - fontMetrics.top; // canvas.drawText(name, rect.left, rect.height() - rect.bottom, paint); float offY = fontTotalHeight / 2; float newY = rect.height() / 2 + offY; canvas.drawText(name, rect.left, newY - 4, paint); return bmp; } //设置@图片和文字混搭 public static CharSequence getExpressionString(Context context, String srcText,DynamicDrawableSpan drawableSpan){ SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append(srcText); String text = builder.toString(); Pattern pattern = Pattern.compile("\\[2f(.*?)\\]"); Matcher matcher = pattern.matcher(text); String atStr,atIndex; SpannableString spannable; int index = 0; while(matcher.find()){ atIndex = matcher.group(1); atStr = "[2f" + atIndex + "]"; index = matcher.start(1) - 3; spannable = new SpannableString(atStr); spannable.setSpan(drawableSpan, 0, spannable.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); builder.replace(index, index + atStr.length(), spannable); } return builder; }}
群员选择界面的代码PersionListActivity
package com.example.hhly_pc.enumuse;import android.app.Activity;import android.app.LoaderManager;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.SystemClock;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.text.Editable;import android.text.TextWatcher;import android.view.View;import android.view.inputmethod.InputMethodManager;import android.widget.EditText;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;import com.example.hhly_pc.enumuse.adapter.BaseRecyclerViewAdapter2;import com.example.hhly_pc.enumuse.adapter.DividerItemDecoration2;import com.example.hhly_pc.enumuse.adapter.TestAdapter;import java.lang.ref.WeakReference;import java.util.ArrayList;import java.util.List;/** * Created by hhly-pc on 2017/1/21. */public class PersionListActivity extends AppCompatActivity implements View.OnClickListener{ private RecyclerView recyclerView; private ImageView ivBack; private ImageView ivSearch; private TextView tv1; private static List<Persion> datas; private EditText editextSeach; private static final int LIST = 0x213; private MyHandler myHandler = new MyHandler(PersionListActivity.this); //LoaderManager /*private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case LIST: SearchContactInfo searchContactInfo = (SearchContactInfo) msg.obj; final List<Persion> persions = searchContactInfo.getAllConctDetailedInfo(); adapter = new TestAdapter(persions,PersionListActivity.this); adapter.setSearchContent(searchContactInfo.getSearchName()); recyclerView.setAdapter(adapter); adapter.notifyDataSetChanged(); adapter.setOnRecyclerViewItemClickListener(new BaseRecyclerViewAdapter2.OnRecyclerViewItemClickListener2() { @Override public void onItemClick(View view, int position) { Intent intent = new Intent(); String usetName = datas.get(position).getUsetName(); String userId = datas.get(position).getUserId(); intent.putExtra("usetName",usetName); intent.putExtra("userId",userId); setResult(200,intent); finish(); } }); } } };*/ private TestAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerView = (RecyclerView) findViewById(R.id.recyclerview); ivBack = (ImageView) findViewById(R.id.iv_back); ivSearch = (ImageView) findViewById(R.id.iv_search); tv1 = (TextView) findViewById(R.id.tv_1); editextSeach = (EditText) findViewById(R.id.editext_seach); ivBack.setOnClickListener(this); ivSearch.setOnClickListener(this); intData(); LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); recyclerView.addItemDecoration(new DividerItemDecoration2(this, LinearLayoutManager.VERTICAL, 1, getResources().getColor(R.color.color_itemMess_divider)));//设置item的分割线 adapter = new TestAdapter(datas,PersionListActivity.this); recyclerView.setAdapter(adapter); adapter.setOnRecyclerViewItemClickListener(new BaseRecyclerViewAdapter2.OnRecyclerViewItemClickListener2() { @Override public void onItemClick(View view, int position) { Intent intent = new Intent(); String usetName = datas.get(position).getUsetName(); String userId = datas.get(position).getUserId(); intent.putExtra("userName",usetName); intent.putExtra("userId",userId); setResult(200,intent); finish(); } }); editextSeach.addTextChangedListener(watcher); } //为了防止Handler引起的内存泄漏,推荐使用一下写法 用static修饰,不会持有外部类的引用 private static class MyHandler extends Handler{ private WeakReference<PersionListActivity> weakReferenceActivity; public MyHandler(Context context){ PersionListActivity persionListActivity = (PersionListActivity) context; weakReferenceActivity = new WeakReference<PersionListActivity>(persionListActivity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); final PersionListActivity weakPersionListActivity2 = weakReferenceActivity.get(); if (weakPersionListActivity2 != null){ //如果这个虚引用为空,不进行操作,否则就进行操作 switch (msg.what) { case LIST: SearchContactInfo searchContactInfo = (SearchContactInfo) msg.obj; final List<Persion> persions = searchContactInfo.getAllConctDetailedInfo(); TestAdapter adapter = new TestAdapter(persions,weakPersionListActivity2); adapter.setSearchContent(searchContactInfo.getSearchName()); weakPersionListActivity2.recyclerView.setAdapter(adapter); adapter.notifyDataSetChanged(); adapter.setOnRecyclerViewItemClickListener(new BaseRecyclerViewAdapter2.OnRecyclerViewItemClickListener2() { @Override public void onItemClick(View view, int position) { Intent intent = new Intent(); String usetName = datas.get(position).getUsetName(); String userId = datas.get(position).getUserId(); intent.putExtra("userName",usetName); intent.putExtra("userId",userId); weakPersionListActivity2.setResult(200,intent); weakPersionListActivity2.finish(); } }); } } } } //初始化数据 private void intData() { datas = new ArrayList<>(); for (int i = 0; i < 25; i++) { datas.add(new Persion("张三" + i,"12345" + i)); } } @Override public void onClick(View v) { int id = v.getId(); switch(id){ case R.id.iv_back: onBackPressed(); break; case R.id.iv_search: tv1.setVisibility(View.GONE); ivSearch.setVisibility(View.GONE); editextSeach.setVisibility(View.VISIBLE); editextSeach.requestFocus(); InputMethodManager inputMethodManager = (InputMethodManager) editextSeach.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.showSoftInput(editextSeach,0); break; } } private TextWatcher watcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { List<Persion> persions = searchUserNames(datas, s.toString()); SearchContactInfo searchContactInfo = new SearchContactInfo(); searchContactInfo.setAllConctDetailedInfo(persions); searchContactInfo.setSearchName(s.toString()); Message msg = new Message(); msg.what = LIST; msg.obj = searchContactInfo; myHandler.sendMessage(msg); } }; public List<Persion> searchUserNames(List<Persion> data,String name){ ArrayList<Persion> atName = new ArrayList<>(); if (data != null && data.size() != 0){ for (Persion persion : data){ if (persion.getUsetName().contains(name)){ atName.add(persion); } } } if (null != atName){ return atName; } return null; } @Override protected void onDestroy() { super.onDestroy(); myHandler.removeCallbacksAndMessages(null); }}
还有一个非常吊的适用于recyclerView的适配器代码BaseRecyclerViewAdapter2
package com.example.hhly_pc.enumuse.adapter;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.example.hhly_pc.enumuse.BaseViewHolder;import java.util.ArrayList;import java.util.List;/** * Created by hhly-pc on 2017/1/18. */public abstract class BaseRecyclerViewAdapter2<T> extends RecyclerView.Adapter<BaseViewHolder2>{ private List<T> mData; //准备数据 private Context mContext; private int mLayoutResId; //页面布局的Id private LayoutInflater mLayoutInflate; //初始化点击监听接口 private OnRecyclerViewItemClickListener2 mOnRecyclerViewItemClickListener; private onRecyclerViewItemLongClickListener2 mOnRecyclerViewItemLongClickListener2; //构造函数 public BaseRecyclerViewAdapter2(List<T> mData, Context mContext, int mLayoutResId) { //这里多对mData和mLayoutResId做判空处理 this.mData = mData == null ? new ArrayList<T>() : new ArrayList<T>(mData); this.mContext = mContext; if (0 != mLayoutResId){ this.mLayoutResId = mLayoutResId; } this.mLayoutInflate = LayoutInflater.from(mContext); } @Override public void onBindViewHolder(BaseViewHolder2 holder, int position) { conver(holder,mData.get(position)); } @Override public BaseViewHolder2 onCreateViewHolder(ViewGroup parent, int viewType) { BaseViewHolder2 baseViewHolder2 = new BaseViewHolder2(mContext,mLayoutInflate.inflate(mLayoutResId,parent,false)); initItemClickListener(baseViewHolder2); return baseViewHolder2; } //初始化点击事件 private void initItemClickListener(final BaseViewHolder2 holder2) { if (mOnRecyclerViewItemClickListener != null){ holder2.itemView.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { mOnRecyclerViewItemClickListener.onItemClick(v,holder2.getLayoutPosition()); } }); } if (mOnRecyclerViewItemLongClickListener2 != null){ holder2.itemView.setOnLongClickListener(new View.OnLongClickListener(){ @Override public boolean onLongClick(View v) { return mOnRecyclerViewItemLongClickListener2.onItemLongClick(v,holder2.getLayoutPosition()); } }); } } @Override public int getItemCount() { return mData.size(); } public void add(int position,T item){ mData.add(position,item); notifyItemInserted(position); } //设置点击事件 public interface OnRecyclerViewItemClickListener2{ void onItemClick(View view, int position); } public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener2 onRecyclerViewItemClickListener2){ this.mOnRecyclerViewItemClickListener = onRecyclerViewItemClickListener2; } public interface onRecyclerViewItemLongClickListener2{ public boolean onItemLongClick(View view,int position); } public void setOnRecyclerViewItemLongClickListener2(onRecyclerViewItemLongClickListener2 onRecyclerViewItemLongClickListener2){ this.mOnRecyclerViewItemLongClickListener2 = onRecyclerViewItemLongClickListener2; } protected abstract void conver(BaseViewHolder2 holder,T item);}
这个适配器的实现类TestAdapter
package com.example.hhly_pc.enumuse.adapter;import android.content.Context;import android.graphics.Color;import android.text.SpannableString;import android.text.SpannableStringBuilder;import android.text.TextUtils;import android.text.style.ForegroundColorSpan;import com.example.hhly_pc.enumuse.Persion;import com.example.hhly_pc.enumuse.R;import java.util.List;/** * Created by hhly-pc on 2017/1/18. */public class TestAdapter extends BaseRecyclerViewAdapter2<Persion> { private String mSearchContent; public TestAdapter(List<Persion> data,Context context){ super(data,context, R.layout.list_item); } @Override protected void conver(BaseViewHolder2 holder, Persion item) { int start = getColorString(item.getUsetName(), mSearchContent); if (start > -1){ System.out.println("start " + start); SpannableStringBuilder builder = new SpannableStringBuilder(item.getUsetName()); ForegroundColorSpan redSpan = new ForegroundColorSpan(Color.RED); builder.setSpan(redSpan,start,start + mSearchContent.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); holder.setText(R.id.tv_1,builder); }else { holder.setText(R.id.tv_1,item.getUsetName()); } } public int getColorString(String userName,String mSearchContent){ int start = -1; if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(mSearchContent)) { if (userName.contains(mSearchContent)) { start = userName.indexOf(mSearchContent); } } return start; } public void setSearchContent(String searchContent){ this.mSearchContent = searchContent; }}
package com.example.hhly_pc.enumuse.adapter;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.util.SparseArray;import android.view.View;import android.widget.TextView;/** * Created by hhly-pc on 2017/1/18. */public class BaseViewHolder2 extends RecyclerView.ViewHolder{ private Context mContext; private final SparseArray<View> views; public View converView; public BaseViewHolder2(Context countext,View itemView) { super(itemView); this.mContext = countext; this.views = new SparseArray<>(); converView = itemView; } public void setText(int viewId,CharSequence s){ TextView view = getView(viewId); view.setText(s); } public <T extends View> T getView(int viewId){ View view = views.get(viewId); if (view == null){ view = converView.findViewById(viewId); views.put(viewId,view); } return (T)view; }}
package com.example.hhly_pc.enumuse;import android.content.Context;import android.util.TypedValue;/** * 常用单位转换的辅助类 */public class DensityUtils { private DensityUtils() { /* cannot be instantiated */ throw new UnsupportedOperationException("cannot be instantiated"); } /** * dp转px * * @param context * @param * @return */ public static int dp2px(Context context, float dpVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics()); } /** * sp转px * * @param context * @param * @return */ public static int sp2px(Context context, float spVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, context.getResources().getDisplayMetrics()); } /** * px转dp * * @param context * @param pxVal * @return */ public static float px2dp(Context context, float pxVal) { final float scale = context.getResources().getDisplayMetrics().density; return (pxVal / scale); } /** * px转sp * * @param pxVal * @return */ public static float px2sp(Context context, float pxVal) { return (pxVal / context.getResources().getDisplayMetrics().scaledDensity); }}
package com.example.hhly_pc.enumuse;import java.util.List;/** * Created by hhly-pc on 2017/1/22. */public class SearchContactInfo { private List<Persion> allConctDetailedInfo; private String searchName; public List<Persion> getAllConctDetailedInfo() { return allConctDetailedInfo; } public void setAllConctDetailedInfo(List<Persion> allConctDetailedInfo) { this.allConctDetailedInfo = allConctDetailedInfo; } public String getSearchName() { return searchName; } public void setSearchName(String searchName) { this.searchName = searchName; }}
结束语:菜鸟一枚,第一次写博客,估计会有很多做的不好的地方,欢迎各位看官指正(看看代码质量咋样)。然后相互交流学习。
- 仿微信、QQ的@功能
- qq空间评论的功能
- 微信实现qq群的qq小冰功能
- QQ抓图功能的提取
- C#实现QQ靠边隐藏的功能
- 关于QQ的一些功能实现
- 关于QQ一些功能的实现(二)
- 简单的QQ分类下拉功能模仿
- 用JQuery实现QQ的页面功能
- 【转载】类似QQ功能的界面
- 实现类似QQ记住密码的功能
- 关于QQ一些功能的实现
- QT实现类似QQ的截图功能
- 类似QQ的好友移动功能
- 测试qq传文件的功能
- 仿QQ变声功能的实现
- vc模仿qq的选择头像功能
- 简单的QQ临时在线聊天功能
- 多进程同步,信号量、管程
- Fragment的信息传递
- FLV学习(六)FlvParser源码阅读(4)解析标签头部
- 青蛙的约会
- 项目中的罪与改
- 仿微信、QQ的@功能
- UVALive 6924 暴力
- 如何快速转载CSDN中的博客 .
- 转载:Linux编程之PING的实现
- hdu 1069 Monkey and Banana
- java JNI 实例 实现调用c++函数
- python之批量读取文件
- 过山车
- C++编程技巧