自定义控件<二> 通讯录的简单实现
来源:互联网 发布:重生天龙八部知乎 编辑:程序博客网 时间:2024/05/21 14:42
自定义控件<二> 通讯录的简单实现
自定义通讯录的核心就是listView中对item的自定义操作,item的联动,拦截,子孩子之间的位置变化;
简单来说就是item作为一个viewGroup对子孩子的简单操作,当然在这里用viewDragHelper很简单可以实现这个需求;
废话不多说,直接上代码:
首先创建listView 实现通讯录列表:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listview = (ListView) findViewById(R.id.listview); listview.setAdapter(new MyAdapter()); }
接下来是关键是对listView中的item的自定义实现
ok~先看下布局文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.itheima.swipedelete96.MainActivity"> <ListView android:id="@+id/listview" android:dividerHeight="2dp" android:divider="@color/colorPrimary" android:layout_width="match_parent" android:layout_height="match_parent"/></RelativeLayout>
item的xml布局实现:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <com.itheima.swipedelete96.SwipeLayout android:id="@+id/swipeLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <!--content布局--> <include layout="@layout/layout_content"/> <!--delete布局--> <include layout="@layout/layout_delete"/> </com.itheima.swipedelete96.SwipeLayout></LinearLayout>
应该有留意到item布局文件中自定义布局SwipeLayout;通过代码实现swipeLayout对子view的操作;
public class SwipeLayout extends FrameLayout { private View content; private View delete; private ViewDragHelper dragHelper; public SwipeLayout(Context context) { this(context, null); } public SwipeLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); dragHelper = ViewDragHelper.create(this, callback); } @Override protected void onFinishInflate() { super.onFinishInflate(); content = getChildAt(0); delete = getChildAt(1); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {// super.onLayout(changed, left, top, right, bottom); content.layout(0, 0, content.getMeasuredWidth(), content.getMeasuredHeight()); int L = content.getMeasuredWidth(); delete.layout(L, 0, L + delete.getMeasuredWidth(), delete.getMeasuredHeight()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean result = dragHelper.shouldInterceptTouchEvent(ev); return result; } float downX, downY; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); if(listener!=null){ listener.onTouchDown(this); } break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); //1.获取移动的dx和dy float dx = moveX - downX; float dy = moveY - downY; //2.判断谁大就是偏向于谁的方向 if(Math.abs(dx)>Math.abs(dy)){ //说明偏向于水平,我们就认为是想滑动条目,则请求listview不要拦截 requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: break; } dragHelper.processTouchEvent(event); return true; } ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return true; } @Override public int getViewHorizontalDragRange(View child) { return 1; } /** * 修正和限制移动的 * @param child * @param left * @param dx * @return */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == content) { //限制content if (left > 0) { left = 0; } else if (left < -delete.getMeasuredWidth()) { left = -delete.getMeasuredWidth(); } } else if (child == delete) { //限制delete if (left > content.getMeasuredWidth()) { left = content.getMeasuredWidth(); } else if (left < (content.getMeasuredWidth() - delete.getMeasuredWidth())) { left = (content.getMeasuredWidth() - delete.getMeasuredWidth()); } } return left; } /** * 伴随移动 * @param changedView * @param left * @param dx */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); //如果移动是content,那么让delete进行伴随移动 if (changedView == content) { int newLeft = delete.getLeft() + dx; delete.layout(newLeft, 0, newLeft + delete.getMeasuredWidth(), delete.getBottom()); } else if (changedView == delete) { //如果移动是delete,那么让content进行伴随移动 int newLeft = content.getLeft() + dx; content.layout(newLeft, 0, newLeft + content.getMeasuredWidth(), content.getBottom()); } //回调接口的方法 if(content.getLeft()==0){ //说明关闭 if(listener!=null){ listener.onClose(SwipeLayout.this); } }else if(content.getLeft()==-delete.getMeasuredWidth()){ //说明打开 if(listener!=null){ listener.onOpen(SwipeLayout.this); } } } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (content.getLeft() > -delete.getMeasuredWidth() / 2) { //关闭 close(); } else { //打开 open(); } } }; /** * 打开 */ public void open() { dragHelper.smoothSlideViewTo(content, -delete.getMeasuredWidth(), 0); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } /** * 关闭 */ public void close() { dragHelper.smoothSlideViewTo(content, 0, 0); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } @Override public void computeScroll() { super.computeScroll(); if (dragHelper.continueSettling(true)) { //再次刷新 ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } } private OnSwipeListener listener; public void setOnSwipeListener(OnSwipeListener listener){ this.listener = listener; } public interface OnSwipeListener{ void onOpen(SwipeLayout swipeLayout); void onClose(SwipeLayout swipeLayout); void onTouchDown(SwipeLayout swipeLayout); }}
在MainActivity中listView设置Adapter实现通讯录的功能;
SwipeLayout currentLayout = null;//用来记录当前打开的SwipeLayout class MyAdapter extends BaseAdapter implements SwipeLayout.OnSwipeListener{ @Override public int getCount() { return Constant.NAMES.length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView== null){ convertView = View.inflate(parent.getContext(), R.layout.adapter_list, null); holder = new ViewHolder(convertView); convertView.setTag(holder); }else { holder = (ViewHolder) convertView.getTag(); } holder.tvName.setText(Constant.NAMES[position]); //给SwipeLayout添加打开关闭的监听器 holder.swipeLayout.setOnSwipeListener(this); return convertView; } @Override public void onOpen(SwipeLayout layout) { //先关闭之间已经打开的 if(currentLayout!=null && currentLayout!=layout){ currentLayout.close(); } //记录一下 currentLayout = layout; } @Override public void onClose(SwipeLayout layout) { //关闭的时候清除一下 if(currentLayout==layout){ currentLayout = null; } } @Override public void onTouchDown(SwipeLayout swipeLayout) { if(currentLayout!=null&¤tLayout!=swipeLayout){ currentLayout.close(); } } } static class ViewHolder { @Bind(R.id.tv_name) TextView tvName; @Bind(R.id.tv_delete) TextView tvDelete; @Bind(R.id.swipeLayout) SwipeLayout swipeLayout; ViewHolder(View view) { ButterKnife.bind(this, view); } }
下面是完整代码:
package com.itheima.swipedelete96;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;import java.util.ArrayList;import butterknife.Bind;import butterknife.ButterKnife;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listview = (ListView) findViewById(R.id.listview); listview.setAdapter(new MyAdapter()); } SwipeLayout currentLayout = null;//用来记录当前打开的SwipeLayout class MyAdapter extends BaseAdapter implements SwipeLayout.OnSwipeListener{ @Override public int getCount() { return Constant.NAMES.length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if(convertView== null){ convertView = View.inflate(parent.getContext(), R.layout.adapter_list, null); holder = new ViewHolder(convertView); convertView.setTag(holder); }else { holder = (ViewHolder) convertView.getTag(); } holder.tvName.setText(Constant.NAMES[position]); //给SwipeLayout添加打开关闭的监听器 holder.swipeLayout.setOnSwipeListener(this); return convertView; } @Override public void onOpen(SwipeLayout layout) { //先关闭之间已经打开的 if(currentLayout!=null && currentLayout!=layout){ currentLayout.close(); } //记录一下 currentLayout = layout; } @Override public void onClose(SwipeLayout layout) { //关闭的时候清除一下 if(currentLayout==layout){ currentLayout = null; } } @Override public void onTouchDown(SwipeLayout swipeLayout) { if(currentLayout!=null&¤tLayout!=swipeLayout){ currentLayout.close(); } } } static class ViewHolder { @Bind(R.id.tv_name) TextView tvName; @Bind(R.id.tv_delete) TextView tvDelete; @Bind(R.id.swipeLayout) SwipeLayout swipeLayout; ViewHolder(View view) { ButterKnife.bind(this, view); } }}package com.itheima.swipedelete96;import android.content.Context;import android.support.v4.view.ViewCompat;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.FrameLayout;/** * Created by lxj on 2016/12/13. */public class SwipeLayout extends FrameLayout { private View content; private View delete; private ViewDragHelper dragHelper; public SwipeLayout(Context context) { this(context, null); } public SwipeLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); dragHelper = ViewDragHelper.create(this, callback); } @Override protected void onFinishInflate() { super.onFinishInflate(); content = getChildAt(0); delete = getChildAt(1); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {// super.onLayout(changed, left, top, right, bottom); content.layout(0, 0, content.getMeasuredWidth(), content.getMeasuredHeight()); int L = content.getMeasuredWidth(); delete.layout(L, 0, L + delete.getMeasuredWidth(), delete.getMeasuredHeight()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean result = dragHelper.shouldInterceptTouchEvent(ev); return result; } float downX, downY; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); if(listener!=null){ listener.onTouchDown(this); } break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); //1.获取移动的dx和dy float dx = moveX - downX; float dy = moveY - downY; //2.判断谁大就是偏向于谁的方向 if(Math.abs(dx)>Math.abs(dy)){ //说明偏向于水平,我们就认为是想滑动条目,则请求listview不要拦截 requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: break; } dragHelper.processTouchEvent(event); return true; } ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return true; } @Override public int getViewHorizontalDragRange(View child) { return 1; } /** * 修正和限制移动的 * @param child * @param left * @param dx * @return */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == content) { //限制content if (left > 0) { left = 0; } else if (left < -delete.getMeasuredWidth()) { left = -delete.getMeasuredWidth(); } } else if (child == delete) { //限制delete if (left > content.getMeasuredWidth()) { left = content.getMeasuredWidth(); } else if (left < (content.getMeasuredWidth() - delete.getMeasuredWidth())) { left = (content.getMeasuredWidth() - delete.getMeasuredWidth()); } } return left; } /** * 伴随移动 * @param changedView * @param left * @param dx */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); //如果移动是content,那么让delete进行伴随移动 if (changedView == content) { int newLeft = delete.getLeft() + dx; delete.layout(newLeft, 0, newLeft + delete.getMeasuredWidth(), delete.getBottom()); } else if (changedView == delete) { //如果移动是delete,那么让content进行伴随移动 int newLeft = content.getLeft() + dx; content.layout(newLeft, 0, newLeft + content.getMeasuredWidth(), content.getBottom()); } //回调接口的方法 if(content.getLeft()==0){ //说明关闭 if(listener!=null){ listener.onClose(SwipeLayout.this); } }else if(content.getLeft()==-delete.getMeasuredWidth()){ //说明打开 if(listener!=null){ listener.onOpen(SwipeLayout.this); } } } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (content.getLeft() > -delete.getMeasuredWidth() / 2) { //关闭 close(); } else { //打开 open(); } } }; /** * 打开 */ public void open() { dragHelper.smoothSlideViewTo(content, -delete.getMeasuredWidth(), 0); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } /** * 关闭 */ public void close() { dragHelper.smoothSlideViewTo(content, 0, 0); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } @Override public void computeScroll() { super.computeScroll(); if (dragHelper.continueSettling(true)) { //再次刷新 ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } } private OnSwipeListener listener; public void setOnSwipeListener(OnSwipeListener listener){ this.listener = listener; } public interface OnSwipeListener{ void onOpen(SwipeLayout swipeLayout); void onClose(SwipeLayout swipeLayout); void onTouchDown(SwipeLayout swipeLayout); }}
阅读全文
1 0
- 自定义控件<二> 通讯录的简单实现
- 简单的自定义控件二
- 通讯录的简单实现
- 通讯录的简单实现
- 通讯录的简单实现
- 简单通讯录的实现
- 简单通讯录的实现
- android的自定义控件简单(二)
- 自定义cell高度实现简单通讯录
- 自定义控件点滴1(自定义控件的简单实现)
- 手机通讯录的简单实现
- Python 实现简单的通讯录
- 实现简单功能的通讯录
- Android简单通讯录的实现
- 二叉排序树实现简单的通讯录
- 实现一个简单的通讯录
- c++实现简单的通讯录
- 简单的通讯录实现方法
- JavaMail给QQ邮箱发邮件报错
- 面向连接/无连接套接字
- Css三列自适应布局
- 我的学习之路_第一章java入门
- Cocos2d-X游戏开发(二)
- 自定义控件<二> 通讯录的简单实现
- SQL的分类
- pads的泪滴
- JS--注册页面
- 网络同步之聊天同步
- 3.activiti工作流-核心API
- Caffe+flask CNN算法服务器搭建
- 并查集详解 (转)
- tomcat配置域名