继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

"安xiaobai"让你的ListView插上翅膀,实现拨号,打电话,侧滑删除等功能

进阶小白
关注TA
已关注
手记 2
粉丝 11
获赞 73

大家好,我是"安xiaobai",我又来和大家分享我自己写的代码了。![图片描述][1]上一次的“处女秀”我介绍的是一个安卓的图片轮播,获得大量的浏览量,所以这次我又来了。如果你没看过,或者又想了解快点这里,点这里,点这里:
http://www.imooc.com/article/9647
这次的demo是通过一个自定义ListView,来实现侧滑删除,拨号,发短信等功能。


       好了上正文。一共有七个文件,四个java文件,三个布局文件。

先上效果图:![图片描述][2]![图片描述][3]
第一个文件:

public class Telphone extends Activity implements MyInterface {

    private ImageView tel_back;
    private SlidingItemListView mListView;
    private TellDAO tellDAO;
    private List mDatas;
    private SlidingItemListViewAdapter adapter;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.telphone);

        initView();
    }

    /**
     * 初始化的方法
     */
    private void initView() {
        tel_back = (ImageView) findViewById(R.id.tel_back);
        tel_back.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                startActivity(new Intent(Telphone.this,MainActivity.class));
                finish();
            }
        });

        //找到ListView控件
        mListView = (SlidingItemListView) findViewById(R.id.listview);

        //实例化一个 查询对象
        tellDAO = new TellDAO(Telphone.this);

        //查询所有数据
        mDatas = tellDAO.getAllTel();
        //将数据传递给 adapter
        adapter = new SlidingItemListViewAdapter(Telphone.this, mDatas,
                mListView.getRightViewWidth());

        //将adapater 配置给 ListView
        mListView.setAdapter(adapter);

        //实现接口    对两个按钮进行监听
        adapter.SetMyInterface(this);

        //实现每一项的监听事件
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                    }
            });
    }

    /**
     * 实现接口   发送消息
     */
    public void Onclick_ll_sendMesg_ll_right(View view, int position) {

        Map map = (Map)mDatas.get(position);
        Uri smsToUri = Uri.parse("smsto:"+map.get("number"));    
        Intent mIntent = new Intent( android.content.Intent.ACTION_SENDTO, smsToUri );  
      //  mIntent.putExtra("sms_body", "sss");  这个是预定短信内容 
        startActivity( mIntent );
    }

    /**
     * 实现接口  拨打电话
     */
    public void Onclick_ll_tellCall_ll_right(View view, int position) {

        Map map = (Map)mDatas.get(position);
        Intent intent = new Intent(Intent.ACTION_DIAL);
        intent.setData(Uri.parse("tel:"+map.get("number")));
        startActivity(intent);
    }
}

这里面有两个方法是实现自定义接口的,通过这两个方法来调用系统的拨号界面,和短信界面。其他的在代码里面有详细的解释。
第二个文件:

public class TellDAO  extends Activity{
    private Context context;

    public TellDAO(Context context){
        this.context = context;
    }

    public List getAllTel(){

        List tell = new ArrayList();
        try {
            Cursor cursor = context.getContentResolver().query(
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    null, null, null, null);
            if (cursor ==null) {
                System.out.println("这里为空");
                return null;
            }
            while (cursor.moveToNext()) {
                Map<String, Object> map = new HashMap<String,Object>();
                map.put("num", cursor.getString(cursor.getColumnIndex(
                        ContactsContract.CommonDataKinds.Phone.CONTACT_ID)));
                map.put("name",cursor.getString(cursor.getColumnIndex(
                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
                map.put("number", cursor.getString(cursor.getColumnIndex(
                        ContactsContract.CommonDataKinds.Phone.NUMBER)));
                tell.add(map);
            }
        } catch (Exception e) {e.printStackTrace();}

        return tell;
    }
}

这是查询系统中通讯录的电话号码。将查询出来的数据保存到map里面在讲map返回给调用者。
第三个文件:

public class SlidingItemListView extends ListView {

    private View mPreItemView;

    private View mCurrentItemView;

    //用户第一点击下去的 X Y的值
    private float mFirstX;
    private float mFirstY;

    private int mRightViewWidth;

    private boolean mIsShown;

    private Boolean mIsHorizontal;

    /**
     * 在构造方法里获取自定义的宽度(右边局部隐藏的宽度)
     * @param context  上下文 
     * @param attrs
     */
    public SlidingItemListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.slidingitemlistview);
        mRightViewWidth = (int) typedArray.getDimension(
                R.styleable.slidingitemlistview_right_width, 200);
        typedArray.recycle();
    }

    /**
     * 重写onInterceptTouchEvent()
     * ACTION_DOWN里获取 mCurrentItemView,mPreItemView,mFirstX,mFirstY
     */
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        float lastX = ev.getX();
        float lastY = ev.getY();

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:

                mIsHorizontal = null;
                mFirstX = lastX;
                mFirstY = lastY;
                int position = pointToPosition((int) mFirstX, (int) mFirstY);

                if (position >= 0) {
                    View view = getChildAt(position - getFirstVisiblePosition());
                    mPreItemView = mCurrentItemView;
                    mCurrentItemView = view;
                }
                break;
            case MotionEvent.ACTION_MOVE:

                break;
            case MotionEvent.ACTION_UP:
                //点击隐藏布局会执行MotionEvent.ACTION_UP
                if (mIsShown) {
                    hideRightView(mCurrentItemView);
                }
                break;
            }

        return super.onInterceptTouchEvent(ev);
    }

    /**
     *重写onTouchEvent()方法
     */
    public boolean onTouchEvent(MotionEvent ev) {

        float lastX = ev.getX();
        float lastY = ev.getY();

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                float dx = lastX - mFirstX;
                float dy = lastY - mFirstY;

                if (mIsHorizontal == null) {
                    if (!judgeScrollDirection(dx, dy)) {
                        // 没判断出方向  ,没有滑动的话就直接退出
                        break;
                    }
                }

                //如果滑动了 
                if (mIsHorizontal) {
                    if (mIsShown && mPreItemView != mCurrentItemView) {
                        //正在展示,前视图不等于后视图   
                        //则隐藏前视图  
                        hideRightView(mPreItemView);
                    }
                    // 在mPreItemView!= mCurrentItemView执行 显示隐藏的宽度  
                    if (dx < 0 && dx > - mRightViewWidth) {
                        mCurrentItemView.scrollTo((int) (-dx), 0);
                    }
                } else {
                    if (mIsShown) {
                        //竖直方向滚动 则隐藏前视图 
                        hideRightView(mPreItemView);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mIsShown) {
                    //点击时如果有在显示的View则隐藏前视图  
                    hideRightView(mPreItemView);
                }

                if (mIsHorizontal != null && mIsHorizontal) {
                    if (mFirstX - lastX > mRightViewWidth / 2) {
                        showRight(mCurrentItemView);
                    } else {
                         // 不到一半则隐藏  
                        hideRightView(mCurrentItemView);
                    }
                    return true;
                }
                break;
            }

        return super.onTouchEvent(ev);
    }

     /** 
     * 展示隐藏的布局 
     * @param mCurrentItemView2 
     */  
    private void showRight(View mCurrentItemView2) {
        mCurrentItemView2.scrollTo(mRightViewWidth, 0);
        mIsShown = true;
    }

    /**
     * 隐藏布局
     */  
    private void hideRightView(View mCurrentItemView2) {
        mCurrentItemView2.scrollTo(0, 0);
        mIsShown = false;

    }

    /**
     * @param 水平距离差 
     * @param 竖直距离差 
     * @return 水平滑动或者竖直滑动都返回true 没有判断出滑动方向则返回false 
     */  
    private boolean judgeScrollDirection(float dx, float dy) {

        if (Math.abs(dx) > 30 && Math.abs(dx) > Math.abs(dy) * 2) {
            mIsHorizontal = true;
            return true;
        }
        if (Math.abs(dy) > 30 && Math.abs(dy) > Math.abs(dx) * 2) {
            mIsHorizontal = false;
            return true;
        }

        return false;
    }

    /**
     * 后面实例化adapter的时候要用
     * 获得右边 的宽度
     * @return
     */
    public int getRightViewWidth() {
        return mRightViewWidth;
    }

    /**
     * 设置 右边的宽度
     * @param mRightViewWidth
     */
    public void setRightViewWidth(int mRightViewWidth) {
        this.mRightViewWidth = mRightViewWidth;
    }

}

这个文件是自定义ListView文件,是实现滑动效果的关键。
第四文件:

public class SlidingItemListViewAdapter extends BaseAdapter {
    //上下文
    private Context mContext;
    //布局文件
    private LayoutInflater mInflater;
    //ListView列表
    private List list;

    //右边的宽度
    private int mRightViewWidth;

    /**
     * 构造方法 初始化一些数据
     * @param mContext  上下文
     * @param list      列表
     * @param mRightViewWidth   右边的宽度
     */
    public SlidingItemListViewAdapter(Context mContext,
            List list, int mRightViewWidth) {
        super();
        this.mContext = mContext;
        this.list = list;
        this.mRightViewWidth = mRightViewWidth;
        mInflater = LayoutInflater.from(mContext);
    }

    //获得数据条目
    public int getCount() {
        return list.size();
    }

    //获得List中的每一个Item
    public Object getItem(int position) {
        return list.get(position);
    }

    //获得itemId
    public long getItemId(int position) {
        return position;
    }

    /**
     * 获得view控件
     */
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder viewHolder;
        onClick listener;

        if (convertView == null) {

            //将ListView中每一个Item的布局文件加载进来
            convertView = mInflater.inflate(R.layout.item_sliding_listview,null);

            //实例化
            viewHolder = new ViewHolder();
            listener = new onClick();

            viewHolder.Re_left = (RelativeLayout) convertView.findViewById(R.id.Re_left);
            viewHolder.ll_right = (LinearLayout) convertView.findViewById(R.id.ll_right);

            //找到 ListView中每一个Iten布局文件中的每一个控件
            viewHolder.num = (TextView) convertView.findViewById(R.id.tv_num_Re_left);
            viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name_Re_left);
            viewHolder.number = (TextView) convertView.findViewById(R.id.tv_path_Re_left);
            viewHolder.tell = (ImageView) convertView.findViewById(R.id.img_tell_Re_left);

            //找到 删除按钮  和  发送短信按钮
            viewHolder.ll_delete = (LinearLayout) convertView.findViewById(R.id.ll_delete_ll_right);
            viewHolder.ll_sendMessgae = (LinearLayout) convertView.findViewById(R.id.ll_sendMessge_ll_right);

            //给三个个按钮设置监听事件
            viewHolder.ll_delete.setOnClickListener(listener);
            viewHolder.ll_sendMessgae.setOnClickListener(listener);
            viewHolder.tell.setOnClickListener(listener);

            //设置tag标记
            convertView.setTag(viewHolder.tell.getId(),listener);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
            // 获取实例  
            listener = (onClick) convertView.getTag(viewHolder.tell.getId());
        }

        // 传递position  
        listener.setPosition(position);

        // 设置布局参数 
        LayoutParams lp_left = new LayoutParams(
                android.widget.LinearLayout.LayoutParams.MATCH_PARENT,
                android.widget.LinearLayout.LayoutParams.MATCH_PARENT);
        //将布局参数 设置给控件
        viewHolder.Re_left.setLayoutParams(lp_left);

        // 设置布局参数
        LayoutParams lp_right = new LayoutParams(mRightViewWidth,
                android.widget.LinearLayout.LayoutParams.MATCH_PARENT);
        //将布局参数 设置给控件
        viewHolder.ll_right.setLayoutParams(lp_right);

        Map map = (Map)list.get(position);
        viewHolder.num.setText(map.get("num").toString());
        viewHolder.name.setText(map.get("name").toString());
        viewHolder.number.setText(map.get("number").toString());

        return convertView;
    }

    /**
     * 内部类   复用监听事件
     * @author First.One
     */
    class onClick implements OnClickListener {

        int position;

        public void setPosition(int position) {
            this.position = position;
        }

        //重写的方法
        public void onClick(View v) {
            switch (v.getId()) {
            case R.id.img_tell_Re_left:
                if (myInterface != null) {
                    myInterface.Onclick_ll_tellCall_ll_right(v,position);
                }else {
                    Toast.makeText(mContext, "程序异常,请稍后再试。",2000).show();
                }
                break;
            //删除
            case R.id.ll_delete_ll_right:
                list.remove(position);
                SlidingItemListViewAdapter.this.notifyDataSetChanged();
                break;
            case R.id.ll_sendMessge_ll_right:
                if (myInterface != null) {
                    myInterface.Onclick_ll_sendMesg_ll_right(v,position);
                }else {
                    Toast.makeText(mContext, "这里是发送短信",
                            Toast.LENGTH_SHORT).show();
                }
                break;
            }
        }
    }

    MyInterface myInterface;

    /**
     * 自己定义置顶的MySetTopInterface接口
     * @author First.One
     * 传递两个参数,一个是被点击的View,另一个是position。
     */
    public interface MyInterface {
        void Onclick_ll_sendMesg_ll_right(View view,int position);
        void Onclick_ll_tellCall_ll_right(View view,int position);
    }

    public void SetMyInterface(MyInterface myInterface) {
        this.myInterface = myInterface;
    }

    /**
     * 内部类  复用item控件里面的view控件
     * @author First.One
     */
    static class ViewHolder {
        //左边的布局文件控件
        RelativeLayout Re_left;
        //右边滑动的控件
        LinearLayout ll_right;

        //删除按钮   发送短信   按钮
        LinearLayout ll_delete;
        LinearLayout ll_sendMessgae;

        //编号、姓名、电话
        TextView num;
        TextView name;
        TextView number;
        //拨打电话       的图标
        ImageView tell;
    }
}

这个文件是自定义Adapter里面重点的是那两个内部类,实现了监听事件和View控件的重复使用。
第五个文件:

<com.example.ashixi.SlidingItemListView 
        xmlns:dyk="http://schemas.android.com/apk/res/com.example.ashixi"
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/bg"
        android:cacheColorHint="#00000000"
        android:divider="#dddbdb"
        android:dividerHeight="1dp"
        android:layout_below="@id/include_id"
        dyk:right_width="120dp" />

这就是一个简单的布局文件,相信你能看懂。
第六个文件:

```。
<resources>

<declare-styleable name="slidingitemlistview">
    <attr name="right_width" format="dimension"></attr>
</declare-styleable>

</resources>

这个文件是控制右便滑动的宽度。在自定义ListView中的构造方法会调用它。
最后一个文件 :
<!-- 左边的布局文件 -->
<RelativeLayout
    android:id="@+id/Re_left"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_num_Re_left"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:gravity="center"
        android:textColor="#fff"
        android:textSize="13sp" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@id/tv_num_Re_left" >

        <TextView
            android:id="@+id/tv_name_Re_left"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:textSize="19sp"
            android:textColor="#fff"/>

        <TextView
            android:id="@+id/tv_path_Re_left"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_name_Re_left"
            android:textColor="#fff"
            android:textSize="15sp" />
    </RelativeLayout>

    <!-- 每一个Item后面的那个图标 -->
    <ImageView
        android:id="@+id/img_tell_Re_left"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="10dp"
        android:scaleType="fitXY"
        android:src="@drawable/tel" />
</RelativeLayout>

<!-- 右滑的图标 -->
<LinearLayout
    android:id="@+id/ll_right"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <!-- 右划删除功能 -->
    <LinearLayout
        android:id="@+id/ll_delete_ll_right"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#F77D48"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="5dp" >

        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:scaleType="fitXY"
            android:src="@drawable/del_icon_normal" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="删除"
            android:textColor="#fff"
            android:textSize="16sp" />
    </LinearLayout>

    <!-- 右滑  发送短信 -->
    <LinearLayout
        android:id="@+id/ll_sendMessge_ll_right"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:background="#FED33F"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="5dp" >

        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:scaleType="fitXY"
            android:src="@drawable/msg" />

        <TextView
            android:id="@+id/tv_sendMes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="短信"
            android:textColor="#fff"
            android:textSize="12sp" />
    </LinearLayout>
</LinearLayout>

这个是LiseView控件中每一个Item的布局文件,也不难。
![图片描述][4]
终于写完了.................心好累。如果你真心想学习这个demo的同学,”俺“保证我这个栗子绝对是最详细的了,没有之一...........好吧!!!!我还是要谦虚点。
![图片描述][5]
  注意:
上面的文件我全部没有引入包,,所以要复制的同学小心哦!!!
上面的文件我全部没有引入包,,所以要复制的同学小心哦!!!
上面的文件我全部没有引入包,,所以要复制的同学小心哦!!!
![图片描述][6]
各位同学,"安xiaobai"我写一个文章也不容易,代码敲了半天,然后又敲了半天的字,如果你觉得文章还可以的话,就点一个推荐呗,,谢谢了。

    严重申明:本文的图片全部来源于网络,如有侵权,请及时联系本人删除。

  [1]: http://img.mukewang.com/57751692000109b603160194.jpg
  [2]: http://img.mukewang.com/5775246b00017bb910801920.jpg
  [3]: http://img.mukewang.com/5775247c0001fde310801920.jpg
  [4]: http://img.mukewang.com/57751d720001108e02880240.gif
  [5]: http://img.mukewang.com/57751dfc00011cc402110240.jpg
  [6]: http://img.mukewang.com/57751ee70001e66003830240.gif
打开App,阅读手记
5人推荐
发表评论
随时随地看视频慕课网APP

热门评论

楼主,我按照你这个做完后,滑动不会完全展示两个按钮,是怎么回事啊?

查看全部评论