Android 自定义View(1)

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"
    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>

</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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值