前面实现了友录的通话记录、联系人、短信三个功能,还剩最后的拨号页面,拨号页面功能需求:
1,页面前半页显示通话记录
2,后半页以网格形式显示一个能拨打电话的拨号键盘
还是按之前的步骤一步一步实现:搭建拨号页面的显示布局文件,构建实体类,构建适配器,业务类的实现,构建工具类的实现方法,最后在fragment中填充数据。
一、布局文件
实现的图例如下图:
整体布局可以用relativelayout或者linearlayout:
上面一个标题栏:中间一个textview--Title,左边一个imageview--添加联系人加号键,右边一个imageview--删除已拨号码键,使用relativelayout或者linearlayout均可
中间一个listview
下面一个图片大背景imageview,该背景带有网格,在网格背景底部覆盖了一个拨号图片imageview。
具体布局代码大家可自行设计,这里就不多赘述。
二、构建实体类
由于页面要呈现的内容都和通话记录数据是一致的,所有直接调用通话记录的实体类即可
Call:
private int _id;//数据记录id
private int photo_id;//头像id
private String name;//姓名
private String number;//电话
private long time;//电话发生的时间(时间戳)
private int type;//type的取值:1,呼入电话,2,呼出电话,3,未接电话
三、适配器的构建
数据源与通话记录是一致的,所以也可以用通话记录的适配器CallAdapter
主要元素:
Context context;
List<Call> calls;
LayoutInflater inflater;//膨胀条目item
CallBiz biz;
构造方法:
public CallAdapter(Context context, List<Call> calls) {
super();
this.context = context;
this.calls = calls;
this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
biz = new CallBiz(context);
}
主要方法:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder vh;
if (convertView==null) {
//viewholder中的属性均是convertView中的一部分
convertView=inflater.inflate(R.layout.call_listview_item, parent,false);
vh=new ViewHolder();
vh.tvName=(TextView) convertView.findViewById(R.id.tvName_call_item);
vh.tvNumber=(TextView) convertView.findViewById(R.id.tvNumber_call_item);
vh.ivAvatar=(ImageView) convertView.findViewById(R.id.ivphoto_call_item);
vh.ivWarn=(ImageView) convertView.findViewById(R.id.ivWarn_call_item);
vh.ivPhoneout=(ImageView) convertView.findViewById(R.id.ivphoneCall_call_item);
vh.time = (TextView) convertView.findViewById(R.id.time_call_item);
convertView.setTag(vh);
}else{
vh=(ViewHolder) convertView.getTag();
}
Call call=getItem(position);
//获取通话记录人头像
biz.asyncgetCallAvatar(call.getPhoto_id(), new onLoadAvatarFinishListener() {
@Override
public void onLoadAvatarFinish(Bitmap bitmap) {
vh.ivAvatar.setImageBitmap(bitmap);
}
});
//用户姓名字体颜色处理,未接电话显示红色联系人
if (call.getType()==3) {
vh.tvName.setTextColor(Color.RED);
}
vh.tvName.setText(call.getName());
vh.tvNumber.setText(call.getNumber());
//呼出小图标的显示
if (call.getType()==2) {
vh.ivPhoneout.setVisibility(View.VISIBLE);//invisible为不可见,但还占着位置,而gone则不可见且不占位置
}else{
vh.ivPhoneout.setVisibility(View.GONE);
}
//陌生人用惊叹号标记
if (call.getName().equals("未知号码")) {
vh.tvName.setTextColor(Color.RED);
vh.ivWarn.setVisibility(View.VISIBLE);
}
//拓展:获得当前系统时间
// Calendar calendar = Calendar.getInstance();
//
// calendar.get(Calendar.DAY_OF_MONTH);
//通话时间的处理
vh.time.setText(biz.getTime(call.getTime()));
return convertView;
}
public void addAll(List<Call> list,boolean flag){
if (flag) {
calls.clear();
}
calls.addAll(list);
notifyDataSetChanged();
}
public class ViewHolder{
TextView tvName;
TextView tvNumber;
ImageView ivAvatar;
ImageView ivWarn;
ImageView ivPhoneout;
TextView time;
}
四、业务类构建
同样也可以用CallBiz的所有方法。
五、工具类方法
在CallBiz中已经都实现过,就不用再构建
六、fragment数据填充
这才是关键的地方,代码如下
主要元素:
ListView listView;
List<Call> calls;
CallAdapter adapter;
CallBiz biz;
View headView;
RelativeLayout dialPad;
TextView tvTitle;
ImageView ivdial,ivLef,ivRight;
//填充拨号键盘的集合:12个元素
private static final String[] keys={"1","2","3","4","5","6","7","8","9","*","0","#"};
oncreate方法中:
View view=inflater.inflate(R.layout.fragment_dial, container, false);
biz=new CallBiz(getActivity());
initHeadView(view);
initListView(view);
initDialPad(view);
return view;
然后依次实现以上方法:
private void initHeadView(View view) {
headView = view.findViewById(R.id.in_dial);
tvTitle=(TextView) headView.findViewById(R.id.tv_headerview_title);
tvTitle.setText("拨打电话");
//标题栏处左侧的添加联系人按钮
ImageView ivleft=(ImageView) headView.findViewById(R.id.iv_headerview_left);
ivleft.setImageResource(R.drawable.ic_add_icon);
ivleft.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//发送一个intent,打开系统的添加联系人界面
Intent intent=new Intent(ContactsContract.Intents.Insert.ACTION);
intent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
//API15(4.0.3)之后添加联系人界面有个bug,点击完成无法直接回到咱们的app
//所以要添加如下声明
intent.putExtra("finishActivityOnSaveCompleted", true);
startActivity(intent);
}
});
//标题栏右侧删除输入的号码
ImageView ivright=(ImageView) headView.findViewById(R.id.iv_headerview_right);
ivright.setImageResource(R.drawable.ic_backspace);
ivright.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String title=tvTitle.getText().toString();
if ("拨打电话".equals(title)) {
return;
}
if (title.length()==1) {
tvTitle.setText("拨打电话");
}else if (title.length()==5||title.length()==10) {
tvTitle.setText(title.subSequence(0, title.length()-2));
}else{
tvTitle.setText(title.subSequence(0, title.length()-1));
}
}
});
}
private void initListView(View view) {
listView=(ListView) view.findViewById(R.id.lv_dial_call);
calls=new ArrayList<Call>();
adapter=new CallAdapter(getActivity(), calls);
listView.setAdapter(adapter);
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
Call call=adapter.getItem(position);
biz.deleteCall(call, adapter);
return true;
}
});
}
private void initDialPad(View view) {
dialPad=(RelativeLayout) view.findViewById(R.id.rl_dial);
DisplayMetrics outMetrics=new DisplayMetrics();
//创建12个textView
getActivity().getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
int width=outMetrics.widthPixels/3;//不能用view.getWidth
int height=(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
50, getActivity().getResources().getDisplayMetrics());
for (int i = 0; i < 12; i++) {
TextView tv=new TextView(getActivity());
tv.setId(i+1);//id必须从1开始
tv.setText(keys[i]);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);//单参数指定的是像素,双参数指定的可以自己定
//居中
tv.setGravity(Gravity.CENTER);
//设定tv的宽度和高度,不能直接用tv.setWidth(),必须要借助容器设定
RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(width, height);
//指定每个tv的相对位置
if (i%3!=0) {
//添加右侧规则
params.addRule(RelativeLayout.RIGHT_OF, i);//anchor表示在谁的id右侧,而tv1的ID1是从1开始的,ID=i+1,目标ID2=ID1-1;
}
if (i>=3) {
//添加下方规则
params.addRule(RelativeLayout.BELOW,i-2);
}
tv.setLayoutParams(params);
//使按键数字按到标题栏
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {//v代表点击哪个tv就是哪个
//拿到点击的拨号键盘上的内容1,2,3,4,5,6·····
TextView textview=(TextView) v;
String number=textview.getText().toString();
String title=tvTitle.getText().toString();
//方法一:限制数字输入的位数
// if (title.length()>=13) {
// return;
// }
if ("拨打电话".equals(title)) {
tvTitle.setText(number);
}else if (title.length()==3||title.length()==8) {
tvTitle.append("-");
tvTitle.append(number);
}else {
tvTitle.append(number);
}
}
});
dialPad.addView(tv);
}
ivdial=(ImageView) view.findViewById(R.id.ivdial_dial);
ivdial.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String number=tvTitle.getText().toString();
if ("拨打电话".equals(number)) {
return;
}
//发送intent,打开系统的电话程序
// Intent intent=new Intent(Intent.ACTION_DIAL);//进入拨号页面,还需再按一下,这种不需要权限
Intent intent=new Intent(Intent.ACTION_CALL);//直接拨打电话需要权限,call_phone
Uri data=Uri.parse("tel:"+number);
intent.setData(data);
startActivity(intent);
}
});
}
@Override
public void onResume() {
super.onResume();
refresh();
}
private void refresh() {
biz.asyncgetAllCalls(new OnLoadCallFinishListener() {
@Override
public void OnLoadCallFinish(List<Call> calls) {
adapter.addAll(calls, true);
}
});
}
七、最后加打电话的权限:
<uses-permission android:name="android.permission.CALL_PHONE"/>
图例如下:
================================================================
至此,友录项目就基本完成,有些细节还需进一步完善,继续努力!