Android自定义View的三种实现方式

曾无好事来相访,赖尔高文一起予。这篇文章主要讲述Android自定义View的三种实现方式相关的知识,希望能为你提供帮助。
  在毕设项目中多处用到自定义控件,一直打算总结一下自定义控件的实现方式,今天就来总结一下吧。在此之前学习了郭霖大神博客上面关于自定义View的几篇博文,感觉受益良多,本文中就参考了其中的一些内容。
总结来说,自定义控件的实现有三种方式,分别是:组合控件、自绘控件和继承控件。下面将分别对这三种方式进行介绍。
(一)组合控件
组合控件,顾名思义就是将一些小的控件组合起来形成一个新的控件,这些小的控件多是系统自带的控件。比如很多应用中普遍使用的标题栏控件,其实用的就是组合控件,那么下面将通过实现一个简单的标题栏自定义控件来说说组合控件的用法。
1、新建一个android项目,创建自定义标题栏的布局文件title_bar.xml:

Android自定义View的三种实现方式

文章图片
1 < ?xml version="1.0" encoding="utf-8"?> 2 < RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3android:layout_width="match_parent" 4android:layout_height="wrap_content" 5android:background="#0000ff" > 6 7< Button 8android:id="@+id/left_btn" 9android:layout_width="wrap_content" 10android:layout_height="wrap_content" 11android:layout_centerVertical="true" 12android:layout_margin="5dp" 13android:background="@drawable/back1_64" /> 14 15< TextView 16android:id="@+id/title_tv" 17android:layout_width="wrap_content" 18android:layout_height="wrap_content" 19android:layout_centerInParent="true" 20android:text="这是标题" 21android:textColor="#ffffff" 22android:textSize="20sp" /> 23 24 < /RelativeLayout>

Android自定义View的三种实现方式

文章图片
可见这个标题栏控件还是比较简单的,其中在左边有一个返回按钮,背景是一张事先准备好的图片back1_64.png,标题栏中间是标题文字。
2、创建一个类TitleView,继承自RelativeLayout:
Android自定义View的三种实现方式

文章图片
1 public class TitleView extends RelativeLayout { 2 3// 返回按钮控件 4private Button mLeftBtn; 5// 标题Tv 6private TextView mTitleTv; 7 8public TitleView(Context context, AttributeSet attrs) { 9super(context, attrs); 10 11// 加载布局 12LayoutInflater.from(context).inflate(R.layout.title_bar, this); 13 14// 获取控件 15mLeftBtn = (Button) findViewById(R.id.left_btn); 16mTitleTv = (TextView) findViewById(R.id.title_tv); 17 18} 19 20// 为左侧返回按钮添加自定义点击事件 21public void setLeftButtonListener(OnClickListener listener) { 22mLeftBtn.setOnClickListener(listener); 23} 24 25// 设置标题的方法 26public void setTitleText(String title) { 27mTitleTv.setText(title); 28} 29 }

Android自定义View的三种实现方式

文章图片
在TitleView中主要是为自定义的标题栏加载了布局,为返回按钮添加事件监听方法,并提供了设置标题文本的方法。
3、在activity_main.xml中引入自定义的标题栏:
Android自定义View的三种实现方式

文章图片
1 < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2android:id="@+id/main_layout" 3android:layout_width="match_parent" 4android:layout_height="match_parent" 5android:orientation="vertical" > 6 7< com.example.test.TitleView 8android:id="@+id/title_bar" 9android:layout_width="match_parent" 10android:layout_height="wrap_content" > 11< /com.example.test.TitleView> 12 13 < /LinearLayout>

Android自定义View的三种实现方式

文章图片
4、在MainActivity中获取自定义的标题栏,并且为返回按钮添加自定义点击事件:
Android自定义View的三种实现方式

文章图片
1private TitleView mTitleBar; 2mTitleBar = (TitleView) findViewById(R.id.title_bar); 3 4mTitleBar.setLeftButtonListener(new OnClickListener() { 5 6@Override 7public void onClick(View v) { 8Toast.makeText(MainActivity.this, "点击了返回按钮", Toast.LENGTH_SHORT) 9.show(); 10finish(); 11} 12});

Android自定义View的三种实现方式

文章图片
5、运行效果如下:
Android自定义View的三种实现方式

文章图片

这样就用组合的方式实现了自定义标题栏,其实经过更多的组合还可以创建出功能更为复杂的自定义控件,比如自定义搜索栏等。
 
(二)自绘控件
自绘控件的内容都是自己绘制出来的,在View的onDraw方法中完成绘制。下面就实现一个简单的计数器,每点击它一次,计数值就加1并显示出来。
1、创建CounterView类,继承自View,实现OnClickListener接口:
Android自定义View的三种实现方式

文章图片
1 public class CounterView extends View implements OnClickListener { 2 3// 定义画笔 4private Paint mPaint; 5// 用于获取文字的宽和高 6private Rect mBounds; 7// 计数值,每点击一次本控件,其值增加1 8private int mCount; 9 10public CounterView(Context context, AttributeSet attrs) { 11super(context, attrs); 12 13// 初始化画笔、Rect 14mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 15mBounds = new Rect(); 16// 本控件的点击事件 17setOnClickListener(this); 18} 19 20@Override 21protected void onDraw(Canvas canvas) { 22super.onDraw(canvas); 23 24mPaint.setColor(Color.BLUE); 25// 绘制一个填充色为蓝色的矩形 26canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint); 27 28mPaint.setColor(Color.YELLOW); 29mPaint.setTextSize(50); 30String text = String.valueOf(mCount); 31// 获取文字的宽和高 32mPaint.getTextBounds(text, 0, text.length(), mBounds); 33float textWidth = mBounds.width(); 34float textHeight = mBounds.height(); 35 36// 绘制字符串 37canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() / 2 38+ textHeight / 2, mPaint); 39} 40 41@Override 42public void onClick(View v) { 43mCount ++; 44 45// 重绘 46invalidate(); 47} 48 49 }

Android自定义View的三种实现方式

文章图片
2、在activity_main.xml中引入该自定义布局:
Android自定义View的三种实现方式

文章图片
1 < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2android:id="@+id/main_layout" 3android:layout_width="match_parent" 4android:layout_height="match_parent" 5android:orientation="vertical" > 6 7< com.example.test.CounterView 8android:id="@+id/counter_view" 9android:layout_width="100dp" 10android:layout_height="100dp" 11android:layout_gravity="center_horizontal|top" 12android:layout_margin="20dp" /> 13 14 < /LinearLayout>

Android自定义View的三种实现方式

文章图片
3、运行效果如下:
Android自定义View的三种实现方式

文章图片

 
(三)继承控件
就是继承已有的控件,创建新控件,保留继承的父控件的特性,并且还可以引入新特性。下面就以支持横向滑动删除列表项的自定义ListView的实现来介绍。
1、创建删除按钮布局delete_btn.xml,这个布局是在横向滑动列表项后显示的:
Android自定义View的三种实现方式

文章图片
1 < ?xml version="1.0" encoding="utf-8"?> 2 < Button xmlns:android="http://schemas.android.com/apk/res/android" 3android:layout_width="wrap_content" 4android:layout_height="wrap_content" 5android:background="#FF0000" 6android:padding="5dp" 7android:text="删除" 8android:textColor="#FFFFFF" 9android:textSize="16sp" > 10 11 < /Button>

Android自定义View的三种实现方式

文章图片
2、创建CustomListView类,继承自ListView,并实现了OnTouchListener和OnGestureListener接口:
Android自定义View的三种实现方式

文章图片
1 public class CustomListView extends ListView implements OnTouchListener, 2OnGestureListener { 3 4// 手势动作探测器 5private GestureDetector mGestureDetector; 6 7// 删除事件监听器 8public interface OnDeleteListener { 9void onDelete(int index); 10} 11 12private OnDeleteListener mOnDeleteListener; 13 14// 删除按钮 15private View mDeleteBtn; 16 17// 列表项布局 18private ViewGroup mItemLayout; 19 20// 选择的列表项 21private int mSelectedItem; 22 23// 当前删除按钮是否显示出来了 24private boolean isDeleteShown; 25 26public CustomListView(Context context, AttributeSet attrs) { 27super(context, attrs); 28 29// 创建手势监听器对象 30mGestureDetector = new GestureDetector(getContext(), this); 31 32// 监听onTouch事件 33setOnTouchListener(this); 34} 35 36// 设置删除监听事件 37public void setOnDeleteListener(OnDeleteListener listener) { 38mOnDeleteListener = listener; 39} 40 41// 触摸监听事件 42@Override 43public boolean onTouch(View v, MotionEvent event) { 44if (isDeleteShown) { 45hideDelete(); 46return false; 47} else { 48return mGestureDetector.onTouchEvent(event); 49} 50} 51 52@Override 53public boolean onDown(MotionEvent e) { 54if (!isDeleteShown) { 55mSelectedItem = pointToPosition((int) e.getX(), (int) e.getY()); 56} 57return false; 58} 59 60@Override 61public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 62float velocityY) { 63// 如果当前删除按钮没有显示出来,并且x方向滑动的速度大于y方向的滑动速度 64if (!isDeleteShown & & Math.abs(velocityX) > Math.abs(velocityY)) { 65mDeleteBtn = LayoutInflater.from(getContext()).inflate( 66R.layout.delete_btn, null); 67 68mDeleteBtn.setOnClickListener(new OnClickListener() { 69 70@Override 71public void onClick(View v) { 72mItemLayout.removeView(mDeleteBtn); 73mDeleteBtn = null; 74isDeleteShown = false; 75mOnDeleteListener.onDelete(mSelectedItem); 76} 77}); 78 79mItemLayout = (ViewGroup) getChildAt(mSelectedItem 80- getFirstVisiblePosition()); 81 82RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( 83LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 84params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 85params.addRule(RelativeLayout.CENTER_VERTICAL); 86 87mItemLayout.addView(mDeleteBtn, params); 88isDeleteShown = true; 89} 90 91return false; 92} 93 94// 隐藏删除按钮 95public void hideDelete() { 96mItemLayout.removeView(mDeleteBtn); 97mDeleteBtn = null; 98isDeleteShown = false; 99} 100 101public boolean isDeleteShown() { 102return isDeleteShown; 103} 104 105/** 106* 后面几个方法本例中没有用到 107*/ 108@Override 109public void onShowPress(MotionEvent e) { 110 111} 112 113@Override 114public boolean onSingleTapUp(MotionEvent e) { 115return false; 116} 117 118@Override 119public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, 120float distanceY) { 121return false; 122} 123 124@Override 125public void onLongPress(MotionEvent e) { 126 127} 128 129 }

Android自定义View的三种实现方式

文章图片
3、定义列表项布局custom_listview_item.xml,它的结构很简单,只包含了一个TextView:
Android自定义View的三种实现方式

文章图片
1 < ?xml version="1.0" encoding="utf-8"?> 2 < RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3android:layout_width="match_parent" 4android:layout_height="match_parent" 5android:descendantFocusability="blocksDescendants" > 6 7< TextView 8android:id="@+id/content_tv" 9android:layout_width="wrap_content" 10android:layout_height="wrap_content" 11android:layout_centerVertical="true" 12android:layout_margin="30dp" 13android:gravity="center_vertical|left" /> 14 15 < /RelativeLayout>

Android自定义View的三种实现方式

文章图片
【Android自定义View的三种实现方式】4、定义适配器类CustomListViewAdapter,继承自ArrayAdapter< String> :
Android自定义View的三种实现方式

文章图片
1 public class CustomListViewAdapter extends ArrayAdapter< String> { 2 3public CustomListViewAdapter(Context context, int textViewResourceId, 4List< String> objects) { 5super(context, textViewResourceId, objects); 6} 7 8@Override 9public View getView(int position, View convertView, ViewGroup parent) { 10View view; 11 12if (convertView == null) { 13view = LayoutInflater.from(getContext()).inflate( 14R.layout.custom_listview_item, null); 15} else { 16view = convertView; 17} 18 19TextView contentTv = (TextView) view.findViewById(R.id.content_tv); 20contentTv.setText(getItem(position)); 21 22return view; 23} 24 25 }

Android自定义View的三种实现方式

文章图片
5、在activity_main.xml中引入自定义的ListView:
Android自定义View的三种实现方式

文章图片
1 < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2android:id="@+id/main_layout" 3android:layout_width="match_parent" 4android:layout_height="match_parent" 5android:orientation="vertical" > 6 7< com.example.test.CustomListView 8android:id="@+id/custom_lv" 9android:layout_width="match_parent" 10android:layout_height="wrap_content" /> 11 12 < /LinearLayout>

Android自定义View的三种实现方式

文章图片
6、在MainActivity中对列表做初始化、设置列表项删除按钮点击事件等处理:
Android自定义View的三种实现方式

文章图片
1 public class MainActivity extends Activity { 2 3// 自定义Lv 4private CustomListView mCustomLv; 5// 自定义适配器 6private CustomListViewAdapter mAdapter; 7// 内容列表 8private List< String> contentList = new ArrayList< String> (); 9 10@Override 11protected void onCreate(Bundle savedInstanceState) { 12super.onCreate(savedInstanceState); 13requestWindowFeature(Window.FEATURE_NO_TITLE); 14setContentView(R.layout.activity_main); 15 16initContentList(); 17 18mCustomLv = (CustomListView) findViewById(R.id.custom_lv); 19mCustomLv.setOnDeleteListener(new OnDeleteListener() { 20 21@Override 22public void onDelete(int index) { 23contentList.remove(index); 24mAdapter.notifyDataSetChanged(); 25} 26}); 27 28mAdapter = new CustomListViewAdapter(this, 0, contentList); 29mCustomLv.setAdapter(mAdapter); 30} 31 32// 初始化内容列表 33private void initContentList() { 34for (int i = 0; i < 20; i++) { 35contentList.add("内容项" + i); 36} 37} 38 39@Override 40public void onBackPressed() { 41if (mCustomLv.isDeleteShown()) { 42mCustomLv.hideDelete(); 43return; 44} 45super.onBackPressed(); 46} 47 48 }

Android自定义View的三种实现方式

文章图片
7、运行效果如下:
Android自定义View的三种实现方式

文章图片

 
Refer:http://blog.csdn.net/guolin_blog/article/details/17357967

    推荐阅读