自定义控件的演示

通常情况下,有三种情况实现自定义控件:

  • 对现有控件进行拓展
    该方法主要是在原生控件的基础上进行拓展,增加新的功能,修改显示UI等,一般是通过onDraw方法进行拓展.
  • 通过组合来实现新的控件
    该方法主要是通过继承合适的ViewGroup,比如,LinearLayout,RelativeLayout等等,再添加一些点击事件,监听事件等指定功能,从而合成复合控件,另外还可以指定一些它自己的属性,让其更具有拓展性.
    • 重新View来实现全新的控件
      该方法主要是通过继承View类,重写onMeasure(),onDraw()等方法进行绘制,并重新onTouchEvent,OnClick等触控事件来实现交互,另外也可以通过引入自定义属性,来拓展该控件的功能.

举例1 ,对TextView的控件进行拓展,通过绘制改变其背景,代码如下

// ViewTest继承TextView,进行初始化,并重写onDraw方法
public class ViewTest extends TextView {

    private Paint mPaint1,mPaint2;
    public  ViewTest(Context context){
        super(context);
    }

    private void init() {
         mPaint1 = new Paint();
         mPaint1.setColor(getResources().getColor(android.R.color.holo_blue_light));
         mPaint1.setStyle(Paint.Style.FILL);

         mPaint2 = new Paint();
         mPaint2.setColor(Color.YELLOW);
         mPaint2.setStyle(Paint.Style.FILL);
    }

    public ViewTest(Context context, AttributeSet attrs){
        super(context,attrs);
        init();
    }

    public ViewTest(Context context,AttributeSet attributeSet,int defStyleAttr){
        super(context,attributeSet,defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint1);
        canvas.drawRect(10,10,getMeasuredWidth()-10,getMeasuredHeight()-10,mPaint2);
        canvas.save();
        canvas.translate(10,5);
        super.onDraw(canvas);
        canvas.restore();
    }
}
// MainActivity 创建ViewTest的对象mViewText
public class MainActivity extends Activity {
   private ViewTest mViewText;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewText = (ViewTest) findViewById(R.id.tv1);
    }
}
// activity_main.xml中装载ViewTest
    <com.example.nft.myapplication.ViewTest //引入的时候 必须要加上packagename路径
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:layout_marginTop="50dp"
        android:layout_marginHorizontal="50dp"
        android:gravity="center"
        android:text="ViewTest"
        android:id="@+id/tv1"/>

举例2
组合控件举例 利用LinearLayout实现一个UI模板的标题栏,左右各一个button,中间是一个显示标题,后面再加一个logo图,并引入自己的属性,来定义按钮的背景 ,字体的大小和方向等等,通过对外暴露接口来实现交互.

/**
 * Created by nft on 17-11-24.
 */

public class ViewTest1 extends LinearLayout {

    private Button mLeftButton,mRightButton;
    private TextView mContent;
    private ImageView mImageView;
    private OnViewClick mlistener;

    private int mPainColor;
    private float mContenSize;
    private Drawable mBackground;
    private boolean mFocus;
    private float mApha;
    private String mTextContent,mLeftButtonText,mRightButtonText;
    private LinearLayout.LayoutParams mLeftParams,mRightParams,mTitleParams,mImageParams;
    private int morientation;
    public ViewTest1(Context context){
        super(context);
    }

    public ViewTest1(Context context, AttributeSet attributeSet){
        super(context,attributeSet);
        Log.i("niuniu","ViewTest1");
        mLeftButton = new Button(context);
        mRightButton = new Button(context);
        mContent = new TextView(context);
        mImageView = new ImageView(context);
        // 获取自定义的样式属性
        TypedArray mTypedArray = context.obtainStyledAttributes(attributeSet,R.styleable.ViewTest1);

        int n = mTypedArray.getIndexCount();
        for (int i = 0;i<n;i++){
            int attr = mTypedArray.getIndex(i);
            switch (attr){
                case R.styleable.ViewTest1_content_text:
                    mTextContent = mTypedArray.getString(R.styleable.ViewTest1_content_text);
                    break;
                case R.styleable.ViewTest1_content_text_apha:
                    mApha = mTypedArray.getFloat(R.styleable.ViewTest1_content_text_apha,1);
                    break;
                case R.styleable.ViewTest1_content_text_color:
                    mPainColor = mTypedArray.getColor(R.styleable.ViewTest1_content_text_color, Color.DKGRAY);
                    break;
                case R.styleable.ViewTest1_content_text_focus:
                    mFocus = mTypedArray.getBoolean(R.styleable.ViewTest1_content_text_focus,false);
                    break;
                case R.styleable.ViewTest1_content_text_size:
                    mContenSize = mTypedArray.getDimension(R.styleable.ViewTest1_content_text_size,10);
                    break;
                case R.styleable.ViewTest1_contet_text_background:
                    mBackground = mTypedArray.getDrawable(R.styleable.ViewTest1_contet_text_background);
                    break;
                case R.styleable.ViewTest1_orientation:
                    morientation = mTypedArray.getInt(R.styleable.ViewTest1_orientation,0);
                    break;
                case R.styleable.ViewTest1_left_button_text:
                    mLeftButtonText = mTypedArray.getString(R.styleable.ViewTest1_left_button_text);
                    break;
                case R.styleable.ViewTest1_right_button_text:
                    mRightButtonText = mTypedArray.getString(R.styleable.ViewTest1_right_button_text);
                    break;
            }
        }

        mTypedArray.recycle();
        mLeftButton.setText(mLeftButtonText);
        mLeftButton.setBackgroundColor(mPainColor);
        mLeftButton.setTextSize(mContenSize);
        mLeftButton.setClickable(mFocus);

        mRightButton.setTextSize(mContenSize);
        mRightButton.setBackgroundColor(mPainColor);
        mRightButton.setText(mRightButtonText);

        mContent.setText(mTextContent);
        mContent.setTextColor(mPainColor);
        mContent.setTextSize(mContenSize);
        mContent.setAlpha(mApha);
        mImageView.setImageDrawable(mBackground);
        mLeftParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        mLeftParams.leftMargin = 20;
        addView(mLeftButton,mLeftParams);

        mTitleParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
        if (morientation == 0){
            mTitleParams.leftMargin = 100;
        }else {
            mTitleParams.rightMargin =100;
        }
        addView(mContent,mTitleParams);

        mRightParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
        mRightParams.leftMargin = 500;
        addView(mRightButton,mRightParams);

        mImageParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
        mImageParams.leftMargin = 100;
        addView(mImageView,mImageParams);
        mLeftButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mlistener.leftClick();
            }
        });

        mRightButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mlistener.rightClick();
            }
        });

    }

    public interface OnViewClick{
        void leftClick();
        void rightClick();
    }

    public void setOnViewClickListener(OnViewClick listener){
        this.mlistener = listener;
    }
    public ViewTest1(Context context,AttributeSet attributeSet,int defStyleAttr){
      super(context,attributeSet,defStyleAttr);
    }

//主页面
public class MainActivity extends Activity {
   private ViewTest mViewText;
   private ViewTest1 mViewTest1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewTest1 = (ViewTest1) findViewById(R.id.tv2);
        mViewTest1.setOnViewClickListener(new ViewTest1.OnViewClick() {
            @Override
            public void leftClick() {
                Toast.makeText(getApplicationContext(),"leftclick",Toast.LENGTH_LONG).show();
            }
            @Override
            public void rightClick() {
                Toast.makeText(getApplicationContext(),"rightclick",Toast.LENGTH_LONG).show();
            }
        });
    }
}

// attrs.xml文件
<resources>
    <declare-styleable name="ViewTest1">
        <attr name="content_text_color" format="color"></attr>
        <attr name="content_text" format="string"></attr>
        <attr name="left_button_text" format="string"></attr>
        <attr name="right_button_text" format="string"></attr>
        <attr name="content_text_size" format="dimension"></attr>
        <attr name="content_text_apha" format="float"></attr>
        <attr name="content_text_focus" format="boolean"></attr>
        <attr name="contet_text_background" format="color|reference"></attr>
        <attr name="orientation">
            <enum name="left" value="0" />
            <enum name="right" value="1" />
        </attr>
    </declare-styleable>
</resources>

// activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" // 引入该控件的命名空间
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.nft.myapplication.MainActivity">
      <com.example.nft.myapplication.ViewTest1 //申明控件时,需要指定完整的包名
        android:id="@+id/tv2"
        android:layout_width="wrap_content"
        android:layout_height="500dp"
        android:layout_margin="50dp"
        app:content_text="添加标题" // 引用自定义属性时,需要使用自定义的xmls的名字
        app:content_text_apha="0.8"
        app:orientation="left"
        app:contet_text_background="@mipmap/ic_launcher"
        app:left_button_text="点击"
        app:right_button_text="添加"
        app:content_text_size="30dp"
        app:content_text_focus="true"
        app:content_text_color="#ff661231"
        />
</LinearLayout>

举例3: 重写View实现全新的控件
实现一个点击后,数字发生变化的自定义View,其步骤:
1、自定义View的属性 同上的例子一样 在attrs.xml文件中定义属性
2、在View的构造方法中获得我们自定义的属性 同上例子一样 通过TypeArray 获取自定义属性
3、重写onMesure // 该步骤不是必须的
4、重写onDraw


public class ViewTest2 extends View {

    private Paint mPaint;
    private Rect mBound;
    private TypedArray mTypeArray;
    private int mTextColor;
    private int mViewWidth =0,mTranslate;
    private LinearGradient mLinearGradient;
    private Matrix mGradientMatix;
    private float mTextSize;
    private String mText;
    public ViewTest2(Context context){
        super(context);
    }
    public ViewTest2(Context context, AttributeSet attributeSet){
        super(context,attributeSet);
        mTypeArray = context.obtainStyledAttributes(attributeSet,R.styleable.ViewTest2);
        mText = mTypeArray.getString(R.styleable.ViewTest2_text);
        mTextColor = mTypeArray.getColor(R.styleable.ViewTest2_text_color, Color.DKGRAY);
        mTextSize = mTypeArray.getDimension(R.styleable.ViewTest2_text_size,10);
        mTypeArray.recycle();
        mBound = new Rect();
        mPaint = new Paint();
        mPaint.setTextSize(mTextSize);
        mPaint.getTextBounds(mText,0,mText.length(),mBound);
        this.setOnClickListener(new OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                mText = randomText();
                postInvalidate();
            }

        });
    }

    private String randomText() {
        Random random = new Random();
        Set<Integer> set = new HashSet<Integer>();
        while (set.size() < 4)
        {
            int randomInt = random.nextInt(10);
            set.add(randomInt);
        }
        StringBuffer sb = new StringBuffer();
        for (Integer i : set)
        {
            sb.append("" + i);
        }

        return sb.toString();
    }


    @Override
    protected void onDraw(Canvas canvas) {
        Log.i("niuniu"," onDraw");
        mPaint.setColor(Color.YELLOW);
        canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);

        mPaint.setColor(mTextColor);
      canvas.drawText(mText,getMeasuredWidth()/2-mBound.width()/4,getMeasuredHeight()/2-mBound.height()/4,mPaint);
      canvas.save();
      super.onDraw(canvas);
      canvas.restore();
      if(mGradientMatix !=null){
          mTranslate += mViewWidth/5;
          if(mTranslate>2*mViewWidth){
              mTranslate = -mViewWidth;
          }
          mGradientMatix.setTranslate(mTranslate,0);
          mLinearGradient.setLocalMatrix(mGradientMatix);
          postInvalidateDelayed(100);
          Log.i("niuniu"," postinvalidate");
      }
    }

    public ViewTest2(Context context, AttributeSet attributeSet, int defStyleAttr){
       super(context,attributeSet,defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int width = measureDimension(widthSize,widthMode);
        int height = measureDimension(heightSize,heightMode);
        setMeasuredDimension(width,height);

    }

    private int measureDimension(int size, int mode) {
        Log.i("niuniu"," measureDimension");
        int result =0;
        if (mode == MeasureSpec.EXACTLY){
            result = size;
        }else {
            result = 500;
            if(mode ==MeasureSpec.AT_MOST){
                result = Math.min(result,size);
                Log.i("niuniu " ," result  " +result);
            }
        }
         return result;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Log.i("niuniu"," onSizeChanged");
        super.onSizeChanged(w, h, oldw, oldh);

        if (mViewWidth ==0){
            mViewWidth = getMeasuredWidth();
            if(mViewWidth>0){
                mLinearGradient = new LinearGradient(0, 0, mViewWidth, 0, new int[]{Color.BLUE, 0x123321, Color.BLUE}, null, Shader.TileMode.CLAMP);
                mPaint.setShader(mLinearGradient);
                mGradientMatix = new Matrix();
            }
        }

    }
}

//log的输出是 measureDimension onSizeChanged onDraw onDraw onDraw ......

猜你喜欢

转载自blog.csdn.net/dakaniu/article/details/78647669