zoukankan      html  css  js  c++  java
  • Android Programming: Pushing the Limits -- Chapter 5: Android User Interface Operations

    多屏幕
    自定义View

    多屏幕

    @、Android 4.2 开始支持多屏幕。

    @、举例:

    public class SecondDisplayDemo extends Activity {
    
        private Presentation mPresentation;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.device_screen);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            setupSecondDisplay();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if(mPresentation != null){
                mPresentation.cancel();
            }
        }
    
        private void setupSecondDisplay(){
            DisplayManager displayManager = (DisplayManager)
                    getSystemService(Context.DISPLAY_SERVICE);
            Display defaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
            Display[] presentationDisplays = displayManager
                    .getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
            if(presentationDisplays.length > 0){
                for(Display presentationDisplay : presentationDisplays){
                    if(presentationDisplay.getDisplayId() != defaultDisplay.getDisplayId()){
                        Presentation presentation =
                                new MyPresentation(this, presentationDisplay);
                        presentation.show();
                        mPresentation = presentation;
                        return;
                    }
                }
            }
            Toast.makeText(this, "No second display found!", Toast.LENGTH_SHORT).show();
        }
    
        private class MyPresentation extends Presentation{
            public MyPresentation(Context context, Display display){
                super(context, display);
                // The View for the second screen
                setContentView(R.layout.second_screen);
            }
        }
    }
    SecondDisplayDemo.java
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        tools:context=".SecondDisplayDemo">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:textSize="32sp"
            android:text="@string/first_screen" />
    
    </RelativeLayout>
    device_screen.xml
    <?xml version="1.0" encoding="utf-8"?>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:paddingLeft="@dimen/activity_horizontal_margin"
                  android:paddingRight="@dimen/activity_horizontal_margin"
                  android:paddingTop="@dimen/activity_vertical_margin"
                  android:paddingBottom="@dimen/activity_vertical_margin"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
        <TextView android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:layout_gravity="center"
                  android:gravity="center"
                  android:text="@string/second_screen_content"
                  android:textSize="32sp" />
    
    </LinearLayout>
    second_screen.xml

    自定义View:

    @、在onAttachedToWindow中加载资源,初始化数据,但最好与大小、位置无关的数据,因为onAttachedToWindow可能在onMeasure之前或之后被调用,这时候可能还不知道view的height和width。

    @、View的绘制有两步:a measure pass and a layout pass。

    https://developer.android.com/guide/topics/ui/how-android-draws.html

    1、  通过measure(int, int)方法确定个组件的height和width,此方法调用可能不止一次,直到所有组件都确定好。此方法会调用onMeasure()。此方法不可被子类覆盖,子类应该重写的是onMeasure()。

    2、  layout(int, int, int, int)通过上一步获取的height和width布局子控件。子类不要覆盖此方法而是onLayout方法。在onLayout方法中可调用子控件的layout方法。

    @、onLayout处理跟大小、位置相关的数据。

    @、onDraw只专注处理绘制工作,而不要有繁重的计算工作。

    @、onTouchEvent处理触摸事件。

    @、MotionEvent

    1、   Each complete gesture is represented by a sequence of motion events with actions that describe pointer state transitions and movements. A gesture starts with a motion event with ACTION_DOWN that provides the location of the first pointer down. As each additional pointer that goes down or up, the framework will generate a motion event with ACTION_POINTER_DOWN or ACTION_POINTER_UP accordingly. Pointer movements are described by motion events with ACTION_MOVE. Finally, a gesture end either when the final pointer goes up as represented by a motion event with ACTION_UP or when gesture is canceled with ACTION_CANCEL.

    2、  getActionIndex:获取pointer的下标,简单理解在MotionEvent中包含一个pointer的数组,当发生ACTION_UP或ACTION_POINTER_UP事件时,相当于从数组中删除一个数据,这样pointer的下标就有可能变化。如果是新的pointer,则新pointer的下标为最小空闲下标;如果是原有的pointer,则此pointer的新下标为原下标减去它前面空闲下标的数量。

    3、  getPointerId:获取pointer的标识符,标识符不会改变,而下标是会改变的。

    4、  findPointerIndex:根据标识符找pointer下标,如果pointer已经失效了则返回-1。

    5、  ACTION_DOWN, ACTION_UP, ACTION_MOVE, ACTION_CANCEL, ACTION_OUTSIDE, ACTION_POINTER_DOWN, ACTION_POINTER_UP.

    @、PointerCoords:存放pointer coordinates数据。(这些数据可以通过MotionEvent类获取吧,那这个类主要作用是什么?传递时少一些数据吗?)

    @、通过Canvas的rotate方法实现旋转。

    @、多点触摸实例:

    例一:PianoKeyBoard

    public class PianoKeyboard extends View {
        public static final String LOG_TAG = "PianoKeyboard";
        public static final int MAX_FINGERS = 5;
        public static final int WHITE_KEYS_COUNT = 7;
        public static final int BLACK_KEYS_COUNT = 5;
        public static final float BLACK_TO_WHITE_WIDTH_RATIO = 0.625f;
        public static final float BLACK_TO_WHITE_HEIGHT_RATIO = 0.54f;
        private Paint mWhiteKeyPaint, mBlackKeyPaint, mBlackKeyHitPaint, mWhiteKeyHitPaint;
        // Support up to five fingers
        private Point[] mFingerPoints = new Point[MAX_FINGERS];
        private int[] mFingerTones = new int[MAX_FINGERS];
        private SoundPool mSoundPool;
        private SparseIntArray mToneToIndexMap = new SparseIntArray();
        private Paint mCKeyPaint, mCSharpKeyPaint, mDKeyPaint,
                mDSharpKeyPaint, mEKeyPaint, mFKeyPaint,
                mFSharpKeyPaint, mGKeyPaint, mGSharpKeyPaint,
                mAKeyPaint, mASharpKeyPaint, mBKeyPaint;
        private Rect mCKey = new Rect(), mCSharpKey = new Rect(),
                mDKey = new Rect(), mDSharpKey = new Rect(),
                mEKey = new Rect(), mFKey = new Rect(),
                mFSharpKey = new Rect(), mGKey = new Rect(),
                mGSharpKey = new Rect(), mAKey = new Rect(),
                mASharpKey = new Rect(), mBKey = new Rect();
        private MotionEvent.PointerCoords mPointerCoords;
    
        public PianoKeyboard(Context context) {
            super(context);
        }
    
        public PianoKeyboard(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public PianoKeyboard(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        protected void onAttachedToWindow() {
            Log.d(LOG_TAG, "In onAttachedToWindow");
            super.onAttachedToWindow();
            mPointerCoords = new MotionEvent.PointerCoords();
            Arrays.fill(mFingerPoints, null);
            Arrays.fill(mFingerTones, -1);
            loadKeySamples(getContext());
            setupPaints();
        }
    
        @Override
    
        protected void onDetachedFromWindow() {
            Log.d(LOG_TAG, "In onDetachedFromWindow");
            super.onDetachedFromWindow();
            releaseKeySamples();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            Log.d(LOG_TAG, "In onMeasure");
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            Log.d(LOG_TAG, "In onLayout");
            super.onLayout(changed, left, top, right, bottom);
            int width = getWidth();
            int height = getHeight();
            int whiteKeyWidth = width / WHITE_KEYS_COUNT;
            int blackKeyWidth = (int) (whiteKeyWidth * BLACK_TO_WHITE_WIDTH_RATIO);
            int blackKeyHeight = (int) (height * BLACK_TO_WHITE_HEIGHT_RATIO);
            mCKey.set(0, 0, whiteKeyWidth, height);
            mCSharpKey.set(whiteKeyWidth - (blackKeyWidth / 2), 0,
                    whiteKeyWidth + (blackKeyWidth / 2), blackKeyHeight);
            mDKey.set(whiteKeyWidth, 0, 2 * whiteKeyWidth, height);
            mDSharpKey.set(2 * whiteKeyWidth - (blackKeyWidth / 2), 0,
                    2 * whiteKeyWidth + (blackKeyWidth / 2), blackKeyHeight);
            mEKey.set(2 * whiteKeyWidth, 0, 3 * whiteKeyWidth, height);
            mFKey.set(3 * whiteKeyWidth, 0, 4 * whiteKeyWidth, height);
            mFSharpKey.set(4 * whiteKeyWidth - (blackKeyWidth / 2), 0,
                    4 * whiteKeyWidth + (blackKeyWidth / 2), blackKeyHeight);
            mGKey.set(4 * whiteKeyWidth, 0, 5 * whiteKeyWidth, height);
            mGSharpKey.set(5 * whiteKeyWidth - (blackKeyWidth / 2), 0,
                    5 * whiteKeyWidth + (blackKeyWidth / 2), blackKeyHeight);
            mAKey.set(5 * whiteKeyWidth, 0, 6 * whiteKeyWidth, height);
            mASharpKey.set(6 * whiteKeyWidth - (blackKeyWidth / 2), 0,
                    6 * whiteKeyWidth + (blackKeyWidth / 2), blackKeyHeight);
            mBKey.set(6 * whiteKeyWidth, 0, 7 * whiteKeyWidth, height);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            Log.d(LOG_TAG, "In onDraw");
            super.onDraw(canvas);
    
            canvas.drawRect(mCKey, mCKeyPaint);
            canvas.drawRect(mDKey, mDKeyPaint);
            canvas.drawRect(mEKey, mEKeyPaint);
            canvas.drawRect(mFKey, mFKeyPaint);
            canvas.drawRect(mGKey, mGKeyPaint);
            canvas.drawRect(mAKey, mAKeyPaint);
            canvas.drawRect(mBKey, mBKeyPaint);
    
            canvas.drawRect(mCSharpKey, mCSharpKeyPaint);
            canvas.drawRect(mDSharpKey, mDSharpKeyPaint);
            canvas.drawRect(mFSharpKey, mFSharpKeyPaint);
            canvas.drawRect(mGSharpKey, mGSharpKeyPaint);
            canvas.drawRect(mASharpKey, mASharpKeyPaint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.d(LOG_TAG, "In onTouchEvent");
            int pointerCount = event.getPointerCount();
            Log.d(LOG_TAG, "In onTouchEvent pointerCount = " + pointerCount);
            int cappedPointerCount = pointerCount > MAX_FINGERS ? MAX_FINGERS : pointerCount;
            Log.d(LOG_TAG, "In onTouchEvent cappedPointerCount = " + cappedPointerCount);
            int actionIndex = event.getActionIndex();
            Log.d(LOG_TAG, "In onTouchEvent actionIndex = " + actionIndex);
            int action = event.getActionMasked();
            Log.d(LOG_TAG, "In onTouchEvent action = " + action);
            int id = event.getPointerId(actionIndex);
            Log.d(LOG_TAG, "In onTouchEvent id = " + id);
    
            if ((action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) && id < MAX_FINGERS) {
                mFingerPoints[id] = new Point((int) event.getX(actionIndex), (int) event.getY(actionIndex));
            } else if ((action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_UP) && id < MAX_FINGERS) {
                mFingerPoints[id] = null;
                invalidateKey(mFingerTones[id]);
                mFingerTones[id] = -1;
            }
    
            for (int i = 0; i < cappedPointerCount; i++) {
                int index = event.findPointerIndex(i);
                if (mFingerPoints[i] != null && index != -1) {
                    mFingerPoints[i].set((int) event.getX(index), (int) event.getY(index));
                    int tone = getToneForPoint(mFingerPoints[i]);
                    invalidateKey(1);
                    if (tone != mFingerTones[i] && tone != -1) {
                        invalidateKey(mFingerTones[i]);
                        mFingerTones[i] = tone;
                        invalidateKey(mFingerTones[i]);
                        if (!isKeyDown(i)) {
                            int poolIndex = mToneToIndexMap.get(mFingerTones[i]);
                            event.getPointerCoords(index, mPointerCoords);
                            float volume = mPointerCoords.getAxisValue(MotionEvent.AXIS_PRESSURE);
                            volume = volume > 1f ? 1f : volume;
                            mSoundPool.play(poolIndex, volume, volume, 0, 0, 1f);
                        }
                    }
                }
            }
    
            updatePaints();
    
            return true;
        }
    
        private void setupPaints() {
            mWhiteKeyPaint = new Paint();
            mWhiteKeyPaint.setStyle(Paint.Style.STROKE);
            mWhiteKeyPaint.setColor(Color.BLACK);
            mWhiteKeyPaint.setStrokeWidth(3);
            mWhiteKeyPaint.setAntiAlias(true);
            mCKeyPaint = mWhiteKeyPaint;
            mDKeyPaint = mWhiteKeyPaint;
            mEKeyPaint = mWhiteKeyPaint;
            mFKeyPaint = mWhiteKeyPaint;
            mGKeyPaint = mWhiteKeyPaint;
            mAKeyPaint = mWhiteKeyPaint;
            mBKeyPaint = mWhiteKeyPaint;
    
            mWhiteKeyHitPaint = new Paint(mWhiteKeyPaint);
            mWhiteKeyHitPaint.setColor(Color.LTGRAY);
            mWhiteKeyHitPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    
            mBlackKeyPaint = new Paint();
            mBlackKeyPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            mBlackKeyPaint.setColor(Color.BLACK);
            mBlackKeyPaint.setAntiAlias(true);
            mCSharpKeyPaint = mBlackKeyPaint;
            mDSharpKeyPaint = mBlackKeyPaint;
            mFSharpKeyPaint = mBlackKeyPaint;
            mGSharpKeyPaint = mBlackKeyPaint;
            mASharpKeyPaint = mBlackKeyPaint;
    
            mBlackKeyHitPaint = new Paint(mBlackKeyPaint);
            mBlackKeyHitPaint.setColor(Color.DKGRAY);
        }
    
        private void loadKeySamples(Context context) {
            mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
    //        mToneToIndexMap.put(R.raw.c, mSoundPool.load(context, R.raw.c, 1));
    //        mToneToIndexMap.put(R.raw.c_sharp, mSoundPool.load(context, R.raw.c_sharp, 1));
    //        mToneToIndexMap.put(R.raw.d, mSoundPool.load(context, R.raw.d, 1));
    //        mToneToIndexMap.put(R.raw.d_sharp, mSoundPool.load(context, R.raw.d_sharp, 1));
    //        mToneToIndexMap.put(R.raw.e, mSoundPool.load(context, R.raw.e, 1));
    //        mToneToIndexMap.put(R.raw.f, mSoundPool.load(context, R.raw.f, 1));
    //        mToneToIndexMap.put(R.raw.f_sharp, mSoundPool.load(context, R.raw.f_sharp, 1));
    //        mToneToIndexMap.put(R.raw.g, mSoundPool.load(context, R.raw.g, 1));
    //        mToneToIndexMap.put(R.raw.g_sharp, mSoundPool.load(context, R.raw.g_sharp, 1));
    //        mToneToIndexMap.put(R.raw.a, mSoundPool.load(context, R.raw.a, 1));
    //        mToneToIndexMap.put(R.raw.a_sharp, mSoundPool.load(context, R.raw.a_sharp, 1));
    //        mToneToIndexMap.put(R.raw.b, mSoundPool.load(context, R.raw.b, 1));
        }
    
        public void releaseKeySamples() {
            mToneToIndexMap.clear();
            mSoundPool.release();
        }
    
        private boolean isKeyDown(int finger) {
            int key = getToneForPoint(mFingerPoints[finger]);
    
            for (int i = 0; i < mFingerPoints.length; i++) {
                if (i != finger) {
                    Point fingerPoint = mFingerPoints[i];
                    if (fingerPoint != null) {
                        int otherKey = getToneForPoint(fingerPoint);
                        if (otherKey == key) {
                            return true;
                        }
                    }
                }
            }
    
            return false;
        }
    
        private void invalidateKey(int tone) {
            invalidate(mCKey);
            switch (tone) {
    //            case R.raw.c:
    //                invalidate(mCKey);
    //                break;
    //            case R.raw.c_sharp:
    //                invalidate(mCSharpKey);
    //                break;
    //            case R.raw.d:
    //                invalidate(mDKey);
    //                break;
    //            case R.raw.d_sharp:
    //                invalidate(mDSharpKey);
    //                break;
    //            case R.raw.e:
    //                invalidate(mEKey);
    //                break;
    //            case R.raw.f:
    //                invalidate(mFKey);
    //                break;
    //            case R.raw.f_sharp:
    //                invalidate(mFSharpKey);
    //                break;
    //            case R.raw.g:
    //                invalidate(mGKey);
    //                break;
    //            case R.raw.g_sharp:
    //                invalidate(mGSharpKey);
    //                break;
    //            case R.raw.a:
    //                invalidate(mAKey);
    //                break;
    //            case R.raw.a_sharp:
    //                invalidate(mASharpKey);
    //                break;
    //            case R.raw.b:
    //                invalidate(mBKey);
    //                break;
            }
        }
    
        private void updatePaints() {
            mCKeyPaint = mWhiteKeyPaint;
            mDKeyPaint = mWhiteKeyPaint;
            mEKeyPaint = mWhiteKeyPaint;
            mFKeyPaint = mWhiteKeyPaint;
            mGKeyPaint = mWhiteKeyPaint;
            mAKeyPaint = mWhiteKeyPaint;
            mBKeyPaint = mWhiteKeyPaint;
            mCSharpKeyPaint = mBlackKeyPaint;
            mDSharpKeyPaint = mBlackKeyPaint;
            mFSharpKeyPaint = mBlackKeyPaint;
            mGSharpKeyPaint = mBlackKeyPaint;
            mASharpKeyPaint = mBlackKeyPaint;
    
            for (Point fingerPoint : mFingerPoints) {
                if (fingerPoint != null) {
                    if (mCSharpKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mCSharpKeyPaint = mBlackKeyHitPaint;
                    } else if (mDSharpKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mDSharpKeyPaint = mBlackKeyHitPaint;
                    } else if (mFSharpKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mFSharpKeyPaint = mBlackKeyHitPaint;
                    } else if (mGSharpKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mGSharpKeyPaint = mBlackKeyHitPaint;
                    } else if (mASharpKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mASharpKeyPaint = mBlackKeyHitPaint;
                    } else if (mCKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mCKeyPaint = mWhiteKeyHitPaint;
                    } else if (mDKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mDKeyPaint = mWhiteKeyHitPaint;
                    } else if (mEKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mEKeyPaint = mWhiteKeyHitPaint;
                    } else if (mFKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mFKeyPaint = mWhiteKeyHitPaint;
                    } else if (mGKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mGKeyPaint = mWhiteKeyHitPaint;
                    } else if (mAKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mAKeyPaint = mWhiteKeyHitPaint;
                    } else if (mBKey.contains(fingerPoint.x, fingerPoint.y)) {
                        mBKeyPaint = mWhiteKeyHitPaint;
                    }
                }
            }
        }
    
        private int getToneForPoint(Point point) {
    //        if (mCSharpKey.contains(point.x, point.y))
    //            return R.raw.c_sharp;
    //        if (mDSharpKey.contains(point.x, point.y))
    //            return R.raw.d_sharp;
    //        if (mFSharpKey.contains(point.x, point.y))
    //            return R.raw.f_sharp;
    //        if (mGSharpKey.contains(point.x, point.y))
    //            return R.raw.g_sharp;
    //        if (mASharpKey.contains(point.x, point.y))
    //            return R.raw.a_sharp;
    //
    //        if (mCKey.contains(point.x, point.y))
    //            return R.raw.c;
    //        if (mDKey.contains(point.x, point.y))
    //            return R.raw.d;
    //        if (mEKey.contains(point.x, point.y))
    //            return R.raw.e;
    //        if (mFKey.contains(point.x, point.y))
    //            return R.raw.f;
    //        if (mGKey.contains(point.x, point.y))
    //            return R.raw.g;
    //        if (mAKey.contains(point.x, point.y))
    //            return R.raw.a;
    //        if (mBKey.contains(point.x, point.y))
    //            return R.raw.b;
    
            return -1;
        }
    }
    PianoKeyboard.java

    例二:PaintView

    public class PaintView extends View {
        public static final int MAX_FINGERS = 5;
        private Path[] mFingerPaths = new Path[MAX_FINGERS];
        private Paint mFingerPaint;
        private ArrayList<Path> mCompletedPaths;
        private RectF mPathBounds = new RectF();
    
        public PaintView(Context context) {
            super(context);
        }
    
        public PaintView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public PaintView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            mCompletedPaths = new ArrayList<Path>();
            mFingerPaint = new Paint();
            mFingerPaint.setAntiAlias(true);
            mFingerPaint.setColor(Color.BLACK);
            mFingerPaint.setStyle(Paint.Style.STROKE);
            mFingerPaint.setStrokeWidth(6);
            mFingerPaint.setStrokeCap(Paint.Cap.BUTT);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            for(Path completedPath : mCompletedPaths){
                canvas.drawPath(completedPath, mFingerPaint);
            }
            for(Path fingerPath : mFingerPaths){
                if(fingerPath != null){
                    canvas.drawPath(fingerPath, mFingerPaint);
                }
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            int pointerCount = event.getPointerCount();
            int cappedPointerCount = pointerCount > MAX_FINGERS ? MAX_FINGERS : pointerCount;
    
            int actionIndex = event.getActionIndex();
            int action = event.getActionMasked();
            int id = event.getPointerId(actionIndex);
    
            if((action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN)
                    && id < MAX_FINGERS){
                mFingerPaths[id] = new Path();
                mFingerPaths[id].moveTo(event.getX(actionIndex), event.getY(actionIndex));
            }else if((action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP)
                    && id < MAX_FINGERS){
                mFingerPaths[id].setLastPoint(event.getX(actionIndex), event.getY(actionIndex));
                mCompletedPaths.add(mFingerPaths[id]);
                mFingerPaths[id].computeBounds(mPathBounds, true);
                invalidate((int) mPathBounds.left, (int) mPathBounds.top,
                        (int) mPathBounds.right, (int) mPathBounds.bottom);
                mFingerPaths[id] = null;
            }
            for(int i = 0; i < cappedPointerCount; i++){
                if(mFingerPaths[i] != null){
                    int index = event.findPointerIndex(i);
                    mFingerPaths[i].lineTo(event.getX(index), event.getY(index));
                    mFingerPaths[i].computeBounds(mPathBounds, true);
                    invalidate((int) mPathBounds.left, (int) mPathBounds.top,
                            (int) mPathBounds.right, (int) mPathBounds.bottom);
                }
            }
    
            return true;
        }
    }
    PaintView.java

    例三:RotationView

    public class RotateView extends View {
        public static final String LOG_TAG = RotateView.class.getSimpleName();
        private static final double MAX_ANGLE = 1e-1;
        private Paint mPaint;
        private float mRotation;
        private Float mPreviousAngle;
    
        public RotateView(Context context) {
            super(context);
        }
    
        public RotateView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public RotateView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
    
            mPaint = new Paint();
            mPaint.setColor(Color.BLACK);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(10);
            mPaint.setAntiAlias(true);
    
            mPreviousAngle = null;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            int width = getWidth();
            int height = getHeight();
            int radius = (int) (width > height ? height * 0.666f : width * 0.666f) / 2;
    
            canvas.drawColor(Color.YELLOW);
            canvas.drawCircle(width / 2, height / 2, radius, mPaint);
            canvas.drawRect(0, 50, 200, 100, mPaint);
            canvas.save();
            canvas.rotate(mRotation, width / 2, height / 2);
            canvas.drawLine(width / 2, height * 0.1f, width / 2, height * 0.9f, mPaint);
            canvas.drawRect(0, 50, 200, 100, mPaint);
            canvas.drawRect(500, 550, 700, 600, mPaint);
            canvas.drawCircle(width / 2, height / 2, radius - 200, mPaint);
            canvas.restore();
           // canvas.save();
            canvas.rotate(mRotation / 2, width / 2, height / 2);
            canvas.drawRect(500, 550, 700, 600, mPaint);
            canvas.restore();
            canvas.drawRect(500, 550, 700, 600, mPaint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if(event.getPointerCount() == 2){
                float currentAngle = (float) angle(event);
                Log.d(LOG_TAG, "In onTouchEvent currentAngle = " + currentAngle);
                Log.d(LOG_TAG, "In onTouchEvent currentAngle degree = " + Math.toDegrees(currentAngle));
                if(mPreviousAngle != null){
                    Log.d(LOG_TAG, "In onTouchEvent mPreviousAngle = " + mPreviousAngle);
                    Log.d(LOG_TAG, "In onTouchEvent mPreviousAngle degree = " + Math.toDegrees(mPreviousAngle));
                    Log.d(LOG_TAG, "In onTouchEvent mRotation = " + mRotation);
                    Log.d(LOG_TAG, "In onTouchEvent mPreviousAngle - currentAngle = " + (mPreviousAngle - currentAngle));
                    Log.d(LOG_TAG, "In onTouchEvent MAX_ANGLE = " + MAX_ANGLE);
                    Log.d(LOG_TAG, "In onTouchEvent clamp = " + clamp(mPreviousAngle - currentAngle, -MAX_ANGLE, MAX_ANGLE));
                    mRotation -= Math.toDegrees(clamp(mPreviousAngle - currentAngle,
                            -MAX_ANGLE, MAX_ANGLE)); // (float)
    //                mRotation -= Math.toDegrees(mPreviousAngle - currentAngle);
                    invalidate();
                }
                mPreviousAngle = currentAngle;
            }else{
                mPreviousAngle = null;
            }
            return true;
        }
    
        private static double angle(MotionEvent event){
            double deltaX = (event.getX(0) - event.getX(1));
            double deltaY = (event.getY(0) - event.getY(1));
            Log.d(LOG_TAG, "In angle x = " + deltaX + ", y = " + deltaY);
            return Math.atan2(deltaY, deltaX);
        }
    
        private static double clamp(double value, double min, double max){
            if(value < min){
                Log.d(LOG_TAG, "In clamp min ---------------------------------------------------------------------------------------------------------------------------------------");
                return min;
            }
            if(value > max){
                Log.d(LOG_TAG, "In clamp max ---------------------------------------------------------------------------------------------------------------------------------------");
                return max;
            }
            return value;
        }
    }
    RotateView.java

    @、OpenGL ES

    https://developer.android.com/guide/topics/graphics/opengl.html

    1、  开源3D引擎Rajawali

    https://github.com/Rajawali/Rajawali

    2、  商用引擎Unity3D

    http://unity3d.com/cn/

  • 相关阅读:
    Unity3D 利用C#实现简单的代理模式Delegate(委托)
    代码删除文件夹,小心资源管理器报错,甚至崩溃【原】
    如何解决“应用程序并行配置不正确”问题?【原】
    STL,ATL,WTL的联系与区别
    C++虚函数表解析(转)
    学各国语言的网站大全
    The 500 Most Commonly Used Words in the English Language
    Top 100 English Verbs
    Top 100 words for advanced learners.
    TOP 100 MISSPELT/MISSPELLED WORDS IN ENGLISH
  • 原文地址:https://www.cnblogs.com/yarightok/p/5630380.html
Copyright © 2011-2022 走看看