您的位置:首页 > 移动开发 > Android开发

Android通话记录ListView实现左滑发短信和右滑打电话

2015-02-09 16:21 316 查看
下午公司篮球赛最后一场,超神队一分憾败。可惜,不过比赛归比赛,重要的是过程中的精彩。

通话记录向左滑动发短信,向右滑动打电话,微信电话本上有这个很便捷的操作,在项目的修改过程中,就仿造微信的交互方式,实现了ListView左右滑动,今天总结一下:

同样由于是在源码环境下编译,所以代码中的资源引用之类地方的可能和常规的稍微不同。

好了 ,shut up and show code:

通话记录清单Activity:

[java] view
plaincopy

package com.android.dialer.calllog;



import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;



import com.android.dialer.DialerApplication;

import com.android.dialer.DialtactsActivity;

import com.android.dialer.calllog.RecordSlideListView.*;



import android.R;

import android.app.Activity;

import android.app.ProgressDialog;

import android.content.AsyncQueryHandler;

import android.content.ComponentName;

import android.content.ContentResolver;

import android.content.Intent;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.graphics.Color;

import android.net.Uri;

import android.os.Bundle;

import android.os.Handler;

import android.provider.CallLog;

import android.util.Log;

import android.view.ContextMenu;

import android.view.KeyEvent;

import android.view.MenuInflater;

import android.view.MenuItem;

import android.view.View;

import android.view.Window;

import android.view.ContextMenu.ContextMenuInfo;

import android.widget.AdapterView;

import android.widget.LinearLayout;

import android.widget.ListView;

import android.widget.RelativeLayout;

import android.widget.TextView;

import android.widget.Toast;

import android.widget.AdapterView.OnItemClickListener;



public class Record extends Activity implements RemoveListener {



private RecordSlideListView callLogListView;

private AsyncQueryHandler asyncQuery;

private RecordAdapter adapter;

private List<RecordBean> callLogs;

public static TextView tvTopBar;



private TextView tvRecordEmptyHint;



public static int inDel = 0;



@Override

protected void onCreate(Bundle savedInstanceState) {



this.requestWindowFeature(Window.FEATURE_NO_TITLE);

super.onCreate(savedInstanceState);

setContentView(com.android.dialer.R.layout.zj_record);



tvTopBar = (TextView) findViewById(com.android.dialer.R.id.textViewRecord);



tvRecordEmptyHint = (TextView) findViewById(com.android.dialer.R.id.zj_record_empty_hint);



callLogListView = (RecordSlideListView) findViewById(com.android.dialer.R.id.call_log_list);

callLogListView.setRemoveListener(this);

asyncQuery = new MyAsyncQueryHandler(getContentResolver());

init();

}



private void init() {

Uri uri = android.provider.CallLog.Calls.CONTENT_URI;

String[] projection = { CallLog.Calls.DATE, CallLog.Calls.NUMBER,

CallLog.Calls.TYPE, CallLog.Calls.CACHED_NAME,

CallLog.Calls._ID, CallLog.Calls.DURATION, };

asyncQuery.startQuery(0, null, uri, projection,

"_id in (select max(_id)from calls group by number)", null,

CallLog.Calls.DEFAULT_SORT_ORDER);

}



private class MyAsyncQueryHandler extends AsyncQueryHandler {

public MyAsyncQueryHandler(ContentResolver cr) {

super(cr);

}



@Override

protected void onQueryComplete(int token, Object cookie, Cursor cursor) {

if (cursor != null && cursor.getCount() > 0) {

callLogs = new ArrayList<RecordBean>();

SimpleDateFormat sfd = new SimpleDateFormat("MM-dd HH:mm");

Date date;

cursor.moveToFirst();

for (int i = 0; i < cursor.getCount(); i++) {

cursor.moveToPosition(i);

date = new Date(cursor.getLong(cursor

.getColumnIndex(CallLog.Calls.DATE)));

String number = cursor.getString(cursor

.getColumnIndex(CallLog.Calls.NUMBER));

int type = cursor.getInt(cursor

.getColumnIndex(CallLog.Calls.TYPE));

String cachedName = cursor.getString(cursor

.getColumnIndex(CallLog.Calls.CACHED_NAME));

int id = cursor.getInt(cursor

.getColumnIndex(CallLog.Calls._ID));

// String duration = cursor.getString(cursor

// .getColumnIndex(CallLog.Calls.DURATION));

RecordBean callLogBean = new RecordBean();

callLogBean.setId(id);

callLogBean.setNumber(number);

callLogBean.setName(cachedName);

if (null == cachedName || "".equals(cachedName)) {

callLogBean.setName(number);

}

callLogBean.setType(type);

callLogBean.setDate(sfd.format(date));

// callLogBean.setDuration(duration);

callLogs.add(callLogBean);

}

if (callLogs.size() > 0) {

setAdapter(callLogs);

tvRecordEmptyHint.setVisibility(View.GONE);



} else {

zjNoRecord();



}

}

super.onQueryComplete(token, cookie, cursor);

}

}



private void setAdapter(List<RecordBean> callLogs) {

adapter = new RecordAdapter(this, callLogs);

callLogListView.setAdapter(adapter);

}



private void zjNoRecord() {

Toast.makeText(this, com.android.dialer.R.string.zjNoRecord,

Toast.LENGTH_LONG).show();

}



public void zjToDialpad(View v) {

// Intent intent = new Intent();

// setResult(100, intent);

Intent intent = new Intent(this,

com.android.dialer.DialtactsActivity.class);

startActivity(intent);

}



public void zjCloseRecord(View v) {

// finish();

}



public void zjToContact(View v) {



ComponentName componetName = new ComponentName(

"com.tchip.contacts.activities",

"com.tchip.contacts.activities.mPeopleActivity");

try {



Intent intent = new Intent();

intent.setComponent(componetName);

startActivity(intent);

//myStartActivity(intent);

// finish();

} catch (Exception err) {

Log.e("ComponentName", "" + err);

}



}



public void myStartActivity(Intent intent)

{

final Intent toBeExecute = intent;

final ProgressDialog progressDialog = ProgressDialog

.show(this,

this.getString(com.android.dialer.R.string.zj_progress_loading),

this.getString(com.android.dialer.R.string.zj_progress_wait));

final Handler handler = new Handler();

final Runnable callback = new Runnable() {

public void run() {

progressDialog.dismiss();

}

};

Thread thread = new Thread() {

@Override

public void run() {

// startActivityForResult(toBeExecute,0);

startActivity(toBeExecute);

handler.post(callback);

}

};

thread.start();

}



public void zjToMsg(View v) {

ComponentName componetName = new ComponentName(

"com.android.mms",

"com.android.mms.ui.ConversationList");

try {

Intent intent = new Intent();

intent.setComponent(componetName);

startActivity(intent);

//myStartActivity(intent);

// finish();

} catch (Exception e) {





}

}



@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

// TODO Auto-generated method stub

if (KeyEvent.KEYCODE_BACK == keyCode) {

Intent intent = new Intent(Intent.ACTION_MAIN);

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

intent.addCategory(Intent.CATEGORY_HOME);

startActivity(intent);

}

return super.onKeyDown(keyCode, event);

}



@Override

protected void onStart() {

// TODO Auto-generated method stub

super.onStart();

}



@Override

protected void onResume() {

// TODO Auto-generated method stub

super.onResume();

}



@Override

protected void onRestart() {

// TODO Auto-generated method stub

init();

super.onRestart();

}



// 滑动之后的回调方法

@Override

public void removeItem(RemoveDirection direction, int position) {

String sildeNum = callLogs.get(position).getNumber(); // zj:获取滑动Item的号码



switch (direction) {

case RIGHT:



tvTopBar.setBackgroundColor(Color.parseColor("#454545"));

tvTopBar.setText(com.android.dialer.R.string.call_log_activity_title);

RecordSlideListView.itemView.setBackgroundColor(Color

.parseColor("#ffffff"));

Uri uri = Uri.parse("tel:" + sildeNum);

Intent intent = new Intent(Intent.ACTION_CALL, uri);

startActivity(intent);

break;

case LEFT:

// Toast.makeText(this, "向左短信 "+ position,

// Toast.LENGTH_SHORT).show();

// rlRecordBack.setBackgroundColor(Color.parseColor("#1C86EE"));

tvTopBar.setBackgroundColor(Color.parseColor("#454545"));

tvTopBar.setText(com.android.dialer.R.string.call_log_activity_title);

RecordSlideListView.itemView.setBackgroundColor(Color

.parseColor("#ffffff"));

Uri uri2 = Uri.parse("smsto:" + sildeNum);

Intent intent2 = new Intent(Intent.ACTION_SENDTO, uri2);

startActivity(intent2);

break;



default:

break;

}

}







}

自定义组件SlideListView:

[java] view
plaincopy

package com.android.dialer.calllog;



import android.content.Context;

import android.graphics.Color;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.VelocityTracker;

import android.view.View;

import android.view.ViewConfiguration;

import android.view.WindowManager;

import android.widget.AdapterView;

import android.widget.ListView;

import android.widget.Scroller;

import android.widget.TextView;



public class RecordSlideListView extends ListView {





private int slidePosition;

private int downY;

private int downX;

private int screenWidth;

public static View itemView;

private Scroller scroller;

private static final int SNAP_VELOCITY = 300;

private VelocityTracker velocityTracker;

private boolean isSlide = false;

private int mTouchSlop;

private RemoveListener mRemoveListener;

private RemoveDirection removeDirection;



public enum RemoveDirection {

RIGHT, LEFT;

}



public RecordSlideListView(Context context) {

this(context, null);

}



public RecordSlideListView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}



public RecordSlideListView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

screenWidth = ((WindowManager) context

.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()

.getWidth();

scroller = new Scroller(context);

mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

}



public void setRemoveListener(RemoveListener removeListener) {

this.mRemoveListener = removeListener;

}



@Override

public boolean dispatchTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN: {

addVelocityTracker(event);



if (!scroller.isFinished()) {

return super.dispatchTouchEvent(event);

}

downX = (int) event.getX();

downY = (int) event.getY();



slidePosition = pointToPosition(downX, downY);



if (slidePosition == AdapterView.INVALID_POSITION) {

return super.dispatchTouchEvent(event);

}



itemView = getChildAt(slidePosition - getFirstVisiblePosition());

break;

}

case MotionEvent.ACTION_MOVE: {

if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY

|| (Math.abs(event.getX() - downX) > mTouchSlop && Math

.abs(event.getY() - downY) < mTouchSlop)) {

isSlide = true;

}

break;

}

case MotionEvent.ACTION_UP:

recycleVelocityTracker();

break;

}



return super.dispatchTouchEvent(event);

}



private void scrollRight() {



// tvTopBar =

// (TextView)findViewById(com.android.dialer.R.id.textViewRecord);

// tvTopBar.setBackgroundColor(Color.parseColor("#32CD32"));

// tvTopBar.setText(com.android.dialer.R.string.zj_slide_right_to_call);



removeDirection = RemoveDirection.RIGHT;

final int delta = (screenWidth + itemView.getScrollX());

scroller.startScroll(itemView.getScrollX(), 0, -delta, 0,

Math.abs(delta));

postInvalidate();

}





private void scrollLeft() {



removeDirection = RemoveDirection.LEFT;

final int delta = (screenWidth - itemView.getScrollX());

scroller.startScroll(itemView.getScrollX(), 0, delta, 0,

Math.abs(delta));

postInvalidate();

}



private void scrollByDistanceX() {

if (itemView.getScrollX() >= screenWidth / 3) {

scrollLeft();

} else if (itemView.getScrollX() <= -screenWidth / 3) {

scrollRight();

} else {

itemView.scrollTo(0, 0);

// zj:恢复Topbar的字和背景颜色

itemView.setBackgroundColor(Color.parseColor("#ffffff"));

Record.tvTopBar.setBackgroundColor(Color.parseColor("#454545"));

Record.tvTopBar

.setText(com.android.dialer.R.string.call_log_activity_title);

}

}



@Override

public boolean onTouchEvent(MotionEvent ev) {

if (isSlide && slidePosition != AdapterView.INVALID_POSITION) {



addVelocityTracker(ev);

final int action = ev.getAction();

int x = (int) ev.getX();

switch (action) {

case MotionEvent.ACTION_MOVE:

int deltaX = downX - x;

downX = x;



if (deltaX > 20) { // 向左sms #D1EEEE

itemView.setBackgroundColor(Color.parseColor("#D1EEEE"));

Record.tvTopBar.setBackgroundColor(Color

.parseColor("#1C86EE"));

Record.tvTopBar

.setText(com.android.dialer.R.string.zj_slide_left_to_sms);



} else if (deltaX < -20) { // 向右call

itemView.setBackgroundColor(Color.parseColor("#D1EEEE"));

Record.tvTopBar.setBackgroundColor(Color

.parseColor("#32CD32"));

Record.tvTopBar

.setText(com.android.dialer.R.string.zj_slide_right_to_call);



}



itemView.scrollBy(deltaX, 0);

return true; // 拖动的时候ListView不滚动

// break;

case MotionEvent.ACTION_UP:

int velocityX = getScrollVelocity();

if (velocityX > SNAP_VELOCITY) {

scrollRight();

} else if (velocityX < -SNAP_VELOCITY) {

scrollLeft();

} else {

scrollByDistanceX();

}



recycleVelocityTracker();

isSlide = false;

break;

}



return true;

}

return super.onTouchEvent(ev);

}



@Override

public void computeScroll() {

if (scroller.computeScrollOffset()) {

itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());



postInvalidate();



if (scroller.isFinished()) {

if (mRemoveListener == null) {

throw new NullPointerException(

"RemoveListener is null, we should called setRemoveListener()");

}



itemView.scrollTo(0, 0);

mRemoveListener.removeItem(removeDirection, slidePosition);

}

}

}





private void addVelocityTracker(MotionEvent event) {

if (velocityTracker == null) {

velocityTracker = VelocityTracker.obtain();

}



velocityTracker.addMovement(event);

}





private void recycleVelocityTracker() {

if (velocityTracker != null) {

velocityTracker.recycle();

velocityTracker = null;

}

}





private int getScrollVelocity() {

velocityTracker.computeCurrentVelocity(1000);

int velocity = (int) velocityTracker.getXVelocity();

return velocity;

}





public interface RemoveListener {

public void removeItem(RemoveDirection direction, int position);

}



}

代码有点长,Adapter的就先不贴了。

转载请注明出处:周木水的CSDN博客 http://blog.csdn.net/zhoumushui
我的GitHub:周木水的GitHub https://github.com/zhoumushui
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: