您的位置:首页 > 移动开发 > Android开发

Android 自定义View(1)

2016-04-26 00:09 423 查看
android自定义View的实现方式有3种,组合控件,继承android控件和继承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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  控件