Android 自定义View(1)
2016-04-26 00:09
423 查看
android自定义View的实现方式有3种,组合控件,继承android控件和继承View。
一、组合控件
这种方式较为简单,基本实现过程是:
1.自定义类继承Linearlayout等;
2.在布局文件中使用系统控件任意组合成预定样式,在构造方法中调用inflate()方法绑定布局文件;或者直接在代码中创建(new)出各种需要的控件;
3.在需要的地方像使用系统控件一样使用它。
注意:当直接在代码中new控件时,可以只实现带1个参数的构造方法,当采用绑定layout的方法时,需要实现至少带2个参数的构造方法;
例:一个自定义标题栏。
layout:
调用它的Activity:
layout:
自定义MyGroupView,继承LinearLayout,实现带2个参数的构造方法,绑定layout。里面包含一个返回的箭头,一个用于显示标题的TextView和一个常见的Set图标。在MyGroupView中监听图标的点击事件,给TextView设置set方法,然后在activity中调用即可。在activity中取得MyGroupView的实例,调用set方法即可任意设置标题。还可以根据项目需要,给自定义控件添加各种方法。
二、继承android控件
只需要继承一个现有的控件,在此基础上增加自己需要的功能即可。
例:一个自定义ListView,支持滑动弹出删除按钮,点击删除item。
MyListView:
popupwindow中只含有一个button,代码如下:
接着在Activity中调用它:
layout:
三、继承View的自绘控件
主要是实现其中的3个方法,onMeasure(),onLayout(),onDraw();
例:一个点击控件自动生成5位乱序数字的View。
在layout布局中使用:我直接插入到之前的例子中:
运行APP,成功实现自定义View。
一、组合控件
这种方式较为简单,基本实现过程是:
1.自定义类继承Linearlayout等;
2.在布局文件中使用系统控件任意组合成预定样式,在构造方法中调用inflate()方法绑定布局文件;或者直接在代码中创建(new)出各种需要的控件;
3.在需要的地方像使用系统控件一样使用它。
注意:当直接在代码中new控件时,可以只实现带1个参数的构造方法,当采用绑定layout的方法时,需要实现至少带2个参数的构造方法;
例:一个自定义标题栏。
package com.wy.customview.view; import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.wy.customview.R; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; /** * Created by wuyong on 2016/4/25. */ public class MyGroupView extends LinearLayout { @Bind(R.id.ivBack) ImageView ivBack; @Bind(R.id.tvTitle) TextView tvTitle; @Bind(R.id.ivSet) ImageView ivSet; Context context; public MyGroupView(Context context, AttributeSet attrs) { super(context, attrs); inflate(context, R.layout.layout_my_group_view, this); ButterKnife.bind(this); this.context=context; } @OnClick({R.id.ivBack, R.id.ivSet}) public void onClick(View view) { switch (view.getId()) { case R.id.ivBack: ( (Activity)context).finish(); //((Activity)getContext()).finish(); break; case R.id.ivSet: // do something``` break; } } public void setTvTitle(String title) { this.tvTitle.setText(title); ; } }
layout:
<?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="48dp" android:background="@color/colorPrimary" > <ImageView android:id="@+id/ivBack" android:layout_width="wrap_content" android:layout_height="24dp" android:src="@mipmap/back" android:layout_marginLeft="10dp" android:layout_centerVertical="true" /> <TextView android:id="@+id/tvTitle" android:text="我的标题" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:layout_centerInParent="true" android:textColor="#ffffff" /> <ImageView android:id="@+id/ivSet" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/set" android:layout_alignParentRight="true" android:layout_centerVertical="true" /> </RelativeLayout>
调用它的Activity:
package com.wy.customview.activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import com.wy.customview.R; import com.wy.customview.view.MyGroupView; import butterknife.Bind; import butterknife.ButterKnife; public class MyGroupActivity extends AppCompatActivity { @Bind(R.id.mvGroup) MyGroupView mvGroup; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_group); ButterKnife.bind(this); mvGroup.setTvTitle("这是组合控件"); } }
layout:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" a 10193 ndroid:layout_height="match_parent" > <com.wy.customview.view.MyGroupView android:id="@+id/mvGroup" android:layout_width="match_parent" android:layout_height="wrap_content"> </com.wy.customview.view.MyGroupView> </RelativeLayout>
自定义MyGroupView,继承LinearLayout,实现带2个参数的构造方法,绑定layout。里面包含一个返回的箭头,一个用于显示标题的TextView和一个常见的Set图标。在MyGroupView中监听图标的点击事件,给TextView设置set方法,然后在activity中调用即可。在activity中取得MyGroupView的实例,调用set方法即可任意设置标题。还可以根据项目需要,给自定义控件添加各种方法。
二、继承android控件
只需要继承一个现有的控件,在此基础上增加自己需要的功能即可。
例:一个自定义ListView,支持滑动弹出删除按钮,点击删除item。
MyListView:
import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.Button; import android.widget.ListView; import android.widget.PopupWindow; import com.wy.customview.R; /** * Created by wuyong on 2016/4/25. */ public class MyListView extends ListView { private int xDown;//手指按下X坐标 private int yDown;//手指按下Y坐标 private int xMove;//手指x方向移动距离 private int yMove;//手指y方向移动距离 private int minMove;//手指移动最小距离 private boolean isSliding; private LayoutInflater inflater; private PopupWindow popupWindow; private int popHeight; private int popWidth; private int position; private View mView;//触摸的当前View private Button button; private DeleteListener deleteListener; public MyListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context){ inflater=LayoutInflater.from(context); minMove= ViewConfiguration.get(context).getScaledTouchSlop(); View view=this.inflater.inflate(R.layout.layout_delete,null); button= (Button) view.findViewById(R.id.btnDelete); popupWindow=new PopupWindow(view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.getContentView().measure(0,0); // popHeight=popupWindow.getContentView().getHeight();//错误 // popWidth=popupWindow.getContentView().getWidth();//错误 popHeight=popupWindow.getContentView().getMeasuredHeight(); popWidth=popupWindow.getContentView().getMeasuredWidth(); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (deleteListener==null) return; deleteListener.onDeleteList(position); popupWindow.dismiss(); } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { int x= (int) ev.getX(); int y= (int) ev.getY(); int action=ev.getAction(); switch (action){ case MotionEvent.ACTION_DOWN: if (popupWindow.isShowing()){ popupWindow.dismiss(); return false; } xDown=x; yDown=y; position=pointToPosition(xDown, yDown); mView=getChildAt(position-getFirstVisiblePosition()); break; case MotionEvent.ACTION_MOVE: xMove=x; yMove=y; int absX=xMove-xDown; int absY=yMove-yDown; //判断是否在向左滑动 if (xMove<xDown&& Math.abs(absX)>minMove&&yMove<yDown&&Math.abs(absY)<minMove){ isSliding=true; } break; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { int action=ev.getAction(); if (isSliding){ switch (action){ case MotionEvent.ACTION_MOVE: int [] location=new int[2]; mView.getLocationOnScreen(location); popupWindow.setAnimationStyle(R.style.popwindow_delete_btn); popupWindow.showAtLocation(mView, Gravity.LEFT|Gravity.TOP, location[0]+mView.getWidth(), location[1]+mView.getHeight()/2-popHeight/2); break; case MotionEvent.ACTION_UP: isSliding=false; break; } return true; } return super.onTouchEvent(ev); } public void setOnDeleteListListener(DeleteListener deleteListener){ this.deleteListener=deleteListener; } public interface DeleteListener{ void onDeleteList(int position); } }
popupwindow中只含有一个button,代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:id="@+id/btnDelete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_red_dark" android:textColor="@android:color/white" android:drawableLeft="@mipmap/ic_delete" android:text="删除" /> </LinearLayout>
接着在Activity中调用它:
public class MyListViewActivity extends AppCompatActivity { @Bind(R.id.myListView) MyListView myListView; private ArrayAdapter<String> adapter; List<String> list=new ArrayList<String>(Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k","l","m","n","o","p","q")); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_list_view); ButterKnife.bind(this); adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,list); myListView.setAdapter(adapter); myListView.setOnDeleteListListener(new MyListView.DeleteListener() { @Override public void onDeleteList(int position) { list.remove(position); adapter.notifyDataSetChanged(); } }); } }
layout:
<?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.wy.customview.view.MyListView android:id="@+id/myListView" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout>
三、继承View的自绘控件
主要是实现其中的3个方法,onMeasure(),onLayout(),onDraw();
例:一个点击控件自动生成5位乱序数字的View。
public class MyText extends View { private Paint paint; private Rect rect; private String text; public MyText(Context context) { super(context); init(); } public MyText(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ paint=new Paint(); rect=new Rect(); text=randomText(); paint.getTextBounds(text,0,text.length(),rect); setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { text=randomText(); postInvalidate(); } }); } private String randomText(){ Random random=new Random(); Set<Integer> set=new HashSet<Integer>(); /* for (int i=0;i<5;i++){ int a=random.nextInt(10); set.add(a); }*/ while (set.size()<5){ int a=random.nextInt(10); set.add(a); } StringBuffer buffer=new StringBuffer(); for (Integer i:set){ buffer.append(String.valueOf(i)); } return buffer.toString(); } /** * 用于设置控件宽高 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * 用于设置控件位置 * @param changed * @param left * @param top * @param right * @param bottom */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); } /** * 绘制 * @param canvas */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); paint.setColor(Color.YELLOW); canvas.drawRect(0,0,getWidth(),getHeight(),paint); paint.setColor(Color.WHITE); paint.setTextSize(30); canvas.drawText(text,getWidth()/2-rect.width()/2,getHeight()/2+rect.height()/2,paint); } }
在layout布局中使用:我直接插入到之前的例子中:
<?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.wy.customview.view.MyGroupView android:id="@+id/mvGroup" android:layout_width="match_parent" android:layout_height="wrap_content"> </com.wy.customview.view.MyGroupView> <com.wy.customview.view.MyText android:layout_width="match_parent" android:layout_height="100dp" android:layout_below="@+id/mvGroup" android:layout_marginTop="20dp" android:layout_centerHorizontal="true" /> </RelativeLayout>
运行APP,成功实现自定义View。
相关文章推荐
- flex 控件的重要属性
- Delphi控件ListView的属性及使用方法详解
- web下载的ActiveX控件自动更新
- WinForm实现按名称递归查找控件的方法
- C#中父窗口和子窗口之间控件互操作实例
- Android编程之Button控件用法实例分析
- Android控件之CheckBox、RadioButton用法实例分析
- 在Android开发中使用自定义组合控件的例子
- MFC中动态创建控件以及事件响应实现方法
- WinForm自定义函数FindControl实现按名称查找控件
- Android控件之ProgressBar用法实例分析
- WinForm拖拽控件生成副本的解决方法
- ASP.NET动态添加用户控件的方法
- ASP.NET的HtmlForm控件学习及Post与Get的区别概述
- WinForm实现移除控件某个事件的方法
- C#分屏控件用法实例
- 可以浮动某个物体的jquery控件用法实例
- jQuery操作基本控件方法实例分析
- jQuery操作表单常用控件方法小结
- C#的winform控件命名规范