本人也是刚开始接触自定view,虽然之前用过不少自定view,但那都是直接copy别人的,作为一个Android工程师,自定view 还是必须要会的.
自定义view 分为三种:
- 自绘控件
- 组合控件
- 继承控件
废话不说了直接上今天写的测试代码
- new一个类 继承listview ,实现两个事件监听器, 触摸事件:OnTouchListener ,和手势事件:OnGestureListener
关于GestureDetector.OnGestureListener 详解
package com.example.animate.test;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.RelativeLayout;
/**
* Created by Administrator on 2016/7/22 0022.
*/
public class Mylistview extends ListView implements View.OnTouchListener, GestureDetector.OnGestureListener {
private GestureDetector gestureDetector;
private OnDeleteListener listener;
private View deleteButton;
private ViewGroup itemLayout;
private int selectedItem;
private boolean isDeleteShown;
public Mylistview(Context context, AttributeSet attrs) {
super(context, attrs);
gestureDetector = new GestureDetector(getContext(), this);
setOnTouchListener(this);
}
public void setOnDeleteListener(OnDeleteListener l) {
listener = l;
}
/*
* 在onTouch()方法中,我们调用GestureDetector的onTouchEvent()方法,将捕捉到的MotionEvent交给GestureDetector
* 来分析是否有合适的callback函数来处理用户的手势
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isDeleteShown) {
itemLayout.removeView(deleteButton);
deleteButton = null;
isDeleteShown = false;
return false;
} else {
return gestureDetector.onTouchEvent(event);
}
}
// 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发
@Override
public boolean onDown(MotionEvent e) {
if (!isDeleteShown) {
selectedItem = pointToPosition((int) e.getX(), (int) e.getY());
}
return false;
}
/*
* 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发
* 注意和onDown()的区别,强调的是没有松开或者拖动的状态
*/
@Override
public void onShowPress(MotionEvent e) {
}
// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
// 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
// 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发
@Override
public void onLongPress(MotionEvent e) {
}
// 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (!isDeleteShown && Math.abs(velocityX) > Math.abs(velocityY)) {
deleteButton = LayoutInflater.from(getContext()).inflate(
R.layout.delete_button, null);
deleteButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
itemLayout.removeView(deleteButton);
deleteButton = null;
isDeleteShown = false;
listener.onDelete(selectedItem);
}
});
itemLayout = (ViewGroup) getChildAt(selectedItem
- getFirstVisiblePosition());
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
params.addRule(RelativeLayout.CENTER_VERTICAL);
itemLayout.addView(deleteButton, params);
isDeleteShown = true;
}
return false;
}
public interface OnDeleteListener {
void onDelete(int index);
}
}
2.然后就是在代码中添加自定义listview
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.example.animate.test.Mylistview
android:id="@+id/mylistview"
android:layout_width="match_parent"
android:layout_height="wrap_content"></com.example.animate.test.Mylistview>
</RelativeLayout>
3.适配器代码 ,跟Activity代码
package com.example.animate.test;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
/**
* Created by Administrator on 2016/7/22 0022.
*/
public class MylistviewAdpter extends BaseAdapter{
public Context mcontext;
public ArrayList<String> mlist;
public MylistviewAdpter(Context context, ArrayList<String> objects) {
mcontext=context;
mlist=objects;
}
@Override
public int getCount() {
return mlist.size();
}
@Override
public Object getItem(int position) {
return mlist.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
view = LayoutInflater.from(mcontext).inflate(R.layout.list_item, null);
} else {
view = convertView;
}
TextView textView = (TextView) view.findViewById(R.id.text_view);
textView.setText(mlist.get(position));
return view;
}
}
package com.example.animate.test;
import android.app.Activity;
import android.os.Bundle;
import java.util.ArrayList;
/**
* Created by Administrator on 2016/7/22 0022.
*/
public class MainActivity3 extends Activity {
private Mylistview myListView;
private MylistviewAdpter adapter;
private ArrayList<String> lists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylistview);
lists = new ArrayList<String>();
lists.add("我");
lists.add("用");
lists.add("双");
lists.add("手");
lists.add("成");
lists.add("就");
lists.add("你");
lists.add("的");
lists.add("梦");
lists.add("想");
myListView = (Mylistview) findViewById(R.id.mylistview);
myListView.setOnDeleteListener(new Mylistview.OnDeleteListener() {
@Override
public void onDelete(int index) {
lists.remove(index);
adapter.notifyDataSetChanged();
}
});
adapter = new MylistviewAdpter(this, lists);
myListView.setAdapter(adapter);
}
}
4.删除按钮布局 (删除按钮布局在 Mylistview中已被调用 ) 和 listview 的item 布局
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/delete_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="删除"
android:background="@color/colorAccent" >
</Button>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:gravity="left|center_vertical"
android:textColor="#000" />
</RelativeLayout>
介绍一个 android:descendantFocusability这个属性:
开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题就出现了,可能会发生点击每一个item的时候没有反应,无法获取的焦点。原因多半是由于在你自己定义的Item中存在诸如ImageButton,Button,CheckBox等子控件(也可以说是Button或者Checkable的子类控件),此时这些子控件会将焦点获取到,所以常常当点击item时变化的是子控件,item本身的点击没有响应。 这时候就可以使用descendantFocusability来解决啦
属性的值有三种:
beforeDescendants:viewgroup会优先其子类控件而获取到焦点
afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
一般我们直接用第三种
最后贴上效果图