Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 自定義控件(二)

自定義控件(二)

編輯:關於Android編程

多點觸控事件簡單介紹

最關鍵的是onTouchEvent這個方法明天應該就會繼續介紹比這要更加多的於事件相關的,比如事件分發等,今天是簡單的事件,不多說,如下:

單指 4個動作 + x值 和 y 值

  @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

重寫onTouchEvent就好了,這裡面有好幾個事件,准確說是一組事件分別是:

MotionEvent.ACTION_DOWN 手指按下 MotionEvent.ACTION_MOVE 手指移動 ACTION_UP 手指抬起 ACTION_CANCEL 取消,這裡看來和up沒什麼區別,和事件分發有關,這裡就不詳細講了,可能明天就學了(笑);

以上就是簡單的介紹,接下來實現一個簡單的案例 簡單的畫畫板

package com.zhouzhou.flowlayoutdemo;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by zhousaito on 2016/9/7.
 */
public class TouchView extends View {

    private Paint mPaint;
    private Path mPath;
    private float mLastX;
    private float mLastY;
    private int mPenColor;
    private int mPenSize;

    public TouchView(Context context) {
        this(context, null);
    }

    public TouchView(Context context, AttributeSet attrs) {
        this(context, attrs, R.style.MyDefStyle);
    }

    public TouchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TouchView, defStyleAttr, R.style.MyDefStyle);
        for (int i = 0; i < array.getIndexCount(); i++) {
            int index = array.getIndex(i);
            switch (index) {
                case R.styleable.TouchView_penColor:
                    mPenColor = array.getColor(index, Color.RED);
                    break;
                case R.styleable.TouchView_penSize:
                    mPenSize = array.getDimensionPixelSize(index, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
                    break;
            }
        }
        mPaint = new Paint();
        mPath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mPenSize);
        mPaint.setColor(mPenColor);
        //畫上線條
        canvas.drawPath(mPath,mPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = event.getX();
                mLastY = event.getY();
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:
                mPath.lineTo(event.getX(), event.getY());
                mLastX = event.getX();
                mLastY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        //重寫繪制
        invalidate();
        return true;
    }
}

這裡寫圖片描述

這裡加了一些屬性和style
在 attrs.xml文件中定義<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">

然後代碼引用上就好了,這樣,簡單的畫板就完成了,哈哈

接下來學一下 Matrix API 我沒怎麼搞懂,還是說一下吧,
用畫圖來解釋吧,Matrix 矩陣,有幾種方式
1.縮放,這個簡單,就要知道mMatrix.postScale(0.5f,0.5f,100,100);
前面是縮放比例,後面是旋轉中心點,不寫就是繞著父控件的左上角縮放
2.旋轉,mMatrix.postRotate(10,100,100); 和縮放差不多,
3.平移 mMatrix.postTranslate(10,10); 就是移動
4.傾斜 mMatrix.postSkew(0.1f,0);
上面4個屬性簡單,我就不寫了,網上一大堆,其實學屬性動畫時候就有學到這些,就傾斜沒有,然而這屬性並不常用,其實我想上gif 圖片的,感覺自己想傻吊一樣,這上gif,太占資源吧,4個屬性4個圖

多手指觸控事件

event.getActionMasked(); 並不是event.getAction(),而是通過event.getActionMasked()這值來判斷,是否多手指的觸控的

MotionEvent.ACTION_POINTER_DOWN 按下
MotionEvent.ACTION_MOVE 移動(和單手指一樣的)
MotionEvent.ACTION_POINTER_UP 抬起

這樣就可以做對應的事情了,
**[0] 主要和單手指沖突時,可以根據event.getPointerCount()
來判斷多少個手指,然後做對應的事情**

繼承ViewGroup 的自定義

今天是繼承ViewGroup來實現自定義控件
FlowLayout(流式布局) 其實很簡單,但是自己沒那麼有邏輯,先不廢話了

    [1] TODO  --> onLayout() -->裡面的值
    [2] 用recycleView來實現一個流式布局
    [3] 必須到onMeasure中寫  measureChildren(); 才可以顯示 不然不能顯示

第一步 繼承viewGroup

public class FlowLayout extends ViewGroup {
    public FlowLayout(Context context) {
        super(context);
    }

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

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

繼承完之後,我們的目標是flowLayout 所以更具需求來寫

 /**
     *       MeasureSpec.UNSPECIFIED
     *       --->子控件自己的大小來顯示,所以怎麼設置值都沒什麼用
     *       二級緩存繪制
     *    [1] TODO  --> onLayout() -->裡面的值
     *    [2] 用recycleView來實現一個流式布局
     *    [3] 必須到onMeasure中寫  measureChildren(); 才可以顯示 不然不能顯示
     * @param changed
     * @param l 父控件的位置
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //流式布局  從左邊到右邊開始排
        int left = l;
        int maxHeight =0;
        int top = t;
        //總寬度
        int width = r - l;

        for (int i = 0; i < getChildCount(); i++) {
            //得到子類控件
            View view = getChildAt(i);
//            Log.e("自定義標簽", "類名==FlowLayout" + "方法名==onLayout=====:" );
            //
            if (left + view.getMeasuredWidth() > width) {
                top += maxHeight;
                maxHeight=0;
                left =l;
            }
            view.layout(left,top,left+view.getMeasuredWidth(),top+view.getMeasuredHeight());
            left+=view.getMeasuredWidth();
            maxHeight = Math.max(maxHeight, view.getMeasuredHeight());
        }

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        /**
         * 要寫這個才能顯示
         */
//        measureChildren(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        measureChildren(widthMeasureSpec,heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

這樣大概實現了一下,因為沒有重寫onMeasure()方法,所以,flowLayout的寬和高不管用,都是滿上了父控件(可以說match_parent,因為表現是充滿的)
這裡寫圖片描述

這樣的話,如果給 flowlayout 加一個padding的話,就看出來,我們的工程並沒有完成
先說好,布局是6個textView和6個機器人圖標交錯,就是幾行復制的,哈哈

 
        

這裡寫圖片描述

就成這樣了,發現是自己沒有處理padding和margin

  @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int left = getPaddingLeft();
        int maxHeight = 0;
        int top = getPaddingTop();
        int width = r - l - getPaddingLeft() - getPaddingRight();
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
            if (left + view.getMeasuredWidth() > width) {
                top += maxHeight;
                maxHeight = 0;
                left = getPaddingLeft();
            }
            view.layout(left + params.leftMargin,
                    top + params.topMargin,
                    left + params.leftMargin + view.getMeasuredWidth(),
                    top + params.topMargin + view.getMeasuredHeight());
            left += view.getMeasuredWidth() + params.leftMargin + params.rightMargin;
            maxHeight = Math.max(maxHeight, view.getMeasuredHeight() + params.topMargin + params.bottomMargin);
        }
    }

加了些padding的處理效果 (背景我去了,看著頭暈(笑))

這裡寫圖片描述

接下來寫onMeasure() 方法,來決定 父控件自身的寬度,從而可以通過高和寬,來進行顯示,這樣,可以平常使用就差不多了,哈哈

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        /**
         * 要寫這個才能顯示
         */
//        measureChildren(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width = 0;
        int height = 0;
        //只要不是固定的  就
        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
            int left = getPaddingLeft();
            int maxHeight = 0;
            int top = getPaddingTop();
            for (int i = 0; i < getChildCount(); i++) {
                View view = getChildAt(i);
                MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
                //相加後,通過原來的
                if (left + view.getMeasuredWidth() + params.rightMargin + params.leftMargin > widthSize - getPaddingRight()) {
                    top += maxHeight;
                    maxHeight = 0;
                    //在這裡得到的是left的,相當於這排排滿了的最大寬度
                    width = Math.max(width, left);
                    left = getPaddingLeft();
                }
                left += view.getMeasuredWidth() + params.rightMargin + params.leftMargin;
                maxHeight = Math.max(maxHeight, view.getMeasuredHeight() + params.topMargin + params.bottomMargin);
            }
            height = maxHeight + top + getPaddingTop() + getPaddingBottom();
            switch (widthMode) {
                case MeasureSpec.AT_MOST:
                    width = Math.min(width,widthSize);
                    break;
                case MeasureSpec.UNSPECIFIED:
                    width = widthSize;
                    break;
            }
            switch (heightMode) {
                case MeasureSpec.AT_MOST:
                    //容器的高度
                    height = Math.min(heightSize, height);
                    break;
                case MeasureSpec.UNSPECIFIED:
                    //容器的高度

                    height = heightSize;
                    break;
            }
        }else {
            //固定的就用自己固定的高和寬
            width =widthSize;
            height = heightSize;
        }

        setMeasuredDimension(width, height);
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

寫完這些,哈哈,基本完成了,簡單的繼承了viewGroup然後,自己寫了一個簡單的容器,flowlayout,效果如下

這裡寫圖片描述

結果,還是比較丑,哈哈

以上就今天的學習類容,哈哈,又寫了2 小時多,努力努力!!!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved