android LabelView 라벨 클 라 우 드 효과 구현

오늘 우 리 는 안 드 로 이 드 의 태그 클 라 우 드 효 과 를 만 들 겠 습 니 다.아직 완벽 하 지 는 않 지만 태그 클 라 우 드 의 효 과 를 충분히 보 여줄 수 있 습 니 다.먼저 효 과 를 살 펴 보 겠 습 니 다.

어,녹화 화면 은 이 정도 밖 에 안 돼.살아 서 봐.오늘 우 리 는 이 효 과 를 실현 해 보 겠 습 니 다.이번 에는 view 를 직접 계승 하 겠 습 니 다.뭐라고 요?이런 거 Surface View 잘 하 는 거 아니에요?왜 view 를 해 야 합 니까?사실은 다 됐 습 니 다.저 는 view 를 선택 한 이 유 는 어,저 는 Surface View 에 대해 잘 모 르 기 때 문 입 니 다.
잔말 말고 다음 부터 코드 를 올 리 겠 습 니 다.

public class LabelView extends View { 
 private static final int DIRECTION_LEFT = 0; //    
 private static final int DIRECTION_RIGHT = 1; //    
 private static final int DIRECITON_TOP = 2; //    
 private static final int DIRECTION_BOTTOM = 3; //    
  
 private boolean isStatic; //     ,   false,    xml : label:is_static="false" 
  
 private int[][] mLocations; //   label    x/y 
 private int[][] mDirections; //   label    x/y 
 private int[][] mSpeeds; //   label x/y   x/y 
 private int[][] mTextWidthAndHeight; //   labeltext    width/height 
  
 private String[] mLabels; //    labels 
 private int[] mFontSizes; //   label      
 //        
 private int[] mColorSchema = {0XFFFF0000, 0XFF00FF00, 0XFF0000FF, 0XFFCCCCCC, 0XFFFFFFFF}; 
  
 private int mTouchSlop; //   touch 
 private int mDownX = -1; 
 private int mDownY = -1; 
 private int mDownIndex = -1; //    index 
  
 private Paint mPaint; 
  
 private Thread mThread; 
  
 private OnItemClickListener mListener; // item     
  
 public LabelView(Context context, AttributeSet attrs) { 
  this(context, attrs, 0); 
 } 
 
 public LabelView(Context context, AttributeSet attrs, int defStyleAttr) { 
  super(context, attrs, defStyleAttr); 
   
  TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LabelView, defStyleAttr, 0); 
  isStatic = ta.getBoolean(R.styleable.LabelView_is_static, false); 
  ta.recycle(); 
   
  mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 
   
  mPaint = new Paint(); 
  mPaint.setAntiAlias(true); 
 } 
  
 @Override 
 protected void onLayout(boolean changed, int left, int top, int right, 
   int bottom) { 
  super.onLayout(changed, left, top, right, bottom); 
  init(); 
 } 
  
 @Override 
 protected void onDraw(Canvas canvas) { 
  if(!hasContents()) { 
   return; 
  } 
   
  for (int i = 0; i < mLabels.length; i++) { 
   mPaint.setTextSize(mFontSizes[i]); 
    
   if(i < mColorSchema.length) mPaint.setColor(mColorSchema[i]); 
   else mPaint.setColor(mColorSchema[i-mColorSchema.length]); 
    
   canvas.drawText(mLabels[i], mLocations[i][0], mLocations[i][1], mPaint); 
  } 
 } 
  
 @Override 
 public boolean onTouchEvent(MotionEvent ev) { 
  switch (ev.getAction()) { 
  case MotionEvent.ACTION_DOWN: 
   mDownX = (int) ev.getX(); 
   mDownY = (int) ev.getY(); 
   mDownIndex = getClickIndex(); 
   break; 
  case MotionEvent.ACTION_UP: 
   int nowX = (int) ev.getX(); 
   int nowY = (int) ev.getY(); 
   if (nowX - mDownX < mTouchSlop && nowY - mDownY < mTouchSlop 
     && mDownIndex != -1 && mListener != null) { 
    mListener.onItemClick(mDownIndex, mLabels[mDownIndex]); 
   } 
    
   mDownX = mDownY = mDownIndex = -1; 
   break; 
  } 
   
  return true; 
 } 
  
 /** 
  *        label    
  * @return label   ,      -1 
  */ 
 private int getClickIndex() { 
  Rect downRect = new Rect(); 
  Rect locationRect = new Rect(); 
  for(int i=0;i<mLocations.length;i++) { 
   downRect.set(mDownX - mTextWidthAndHeight[i][0], mDownY 
     - mTextWidthAndHeight[i][1], mDownX 
     + mTextWidthAndHeight[i][0], mDownY 
     + mTextWidthAndHeight[i][1]); 
    
   locationRect.set(mLocations[i][0], mLocations[i][1], 
     mLocations[i][0] + mTextWidthAndHeight[i][0], 
     mLocations[i][1] + mTextWidthAndHeight[i][1]); 
    
   if(locationRect.intersect(downRect)) { 
    return i; 
   } 
  } 
  return -1; 
 } 
  
 /** 
  *             postInvalidate 
  */ 
 private void run() { 
  if(mThread != null && mThread.isAlive()) { 
   return; 
  } 
   
  mThread = new Thread(mStartRunning); 
  mThread.start(); 
 } 
  
 private Runnable mStartRunning = new Runnable() { 
  @Override 
  public void run() { 
   for(;;) { 
    SystemClock.sleep(100); 
     
    for (int i = 0; i < mLabels.length; i++) { 
     if (mLocations[i][0] <= getPaddingLeft()) { 
      mDirections[i][0] = DIRECTION_RIGHT; 
     } 
      
     if (mLocations[i][0] >= getMeasuredWidth() 
       - getPaddingRight() - mTextWidthAndHeight[i][0]) { 
      mDirections[i][0] = DIRECTION_LEFT; 
     } 
      
     if(mLocations[i][1] <= getPaddingTop() + mTextWidthAndHeight[i][1]) { 
      mDirections[i][1] = DIRECTION_BOTTOM; 
     } 
      
     if (mLocations[i][1] >= getMeasuredHeight() - getPaddingBottom()) { 
      mDirections[i][1] = DIRECITON_TOP; 
     } 
      
     int xSpeed = 1; 
     int ySpeed = 2; 
      
     if(i < mSpeeds.length) { 
      xSpeed = mSpeeds[i][0]; 
      ySpeed = mSpeeds[i][1]; 
     } 
     else { 
      xSpeed = mSpeeds[i-mSpeeds.length][0]; 
      ySpeed = mSpeeds[i-mSpeeds.length][1]; 
     } 
      
     mLocations[i][0] += mDirections[i][0] == DIRECTION_RIGHT ? xSpeed : -xSpeed; 
     mLocations[i][1] += mDirections[i][1] == DIRECTION_BOTTOM ? ySpeed : -ySpeed; 
    } 
     
    postInvalidate(); 
   } 
  } 
 }; 
  
 /** 
  *      、  、label   
  *       
  */ 
 private void init() { 
  if(!hasContents()) { 
   return; 
  } 
   
  int minX = getPaddingLeft(); 
  int minY = getPaddingTop(); 
  int maxX = getMeasuredWidth() - getPaddingRight(); 
  int maxY = getMeasuredHeight() - getPaddingBottom(); 
   
  Rect textBounds = new Rect(); 
   
  for (int i = 0; i < mLabels.length; i++) { 
   int[] location = new int[2]; 
   location[0] = minX + (int) (Math.random() * maxX); 
   location[1] = minY + (int) (Math.random() * maxY); 
    
   mLocations[i] = location; 
   mFontSizes[i] = 15 + (int) (Math.random() * 30); 
   mDirections[i][0] = Math.random() > 0.5 ? DIRECTION_RIGHT : DIRECTION_LEFT; 
   mDirections[i][1] = Math.random() > 0.5 ? DIRECTION_BOTTOM : DIRECITON_TOP; 
    
   mPaint.setTextSize(mFontSizes[i]); 
   mPaint.getTextBounds(mLabels[i], 0, mLabels[i].length(), textBounds); 
   mTextWidthAndHeight[i][0] = textBounds.width(); 
   mTextWidthAndHeight[i][1] = textBounds.height(); 
  } 
   
  if(!isStatic) run(); 
 } 
  
 /** 
  *     label 
  * @return true or false 
  */ 
 private boolean hasContents() { 
  return mLabels != null && mLabels.length > 0; 
 } 
 
 /** 
  *   labels 
  * @see setLabels(String[] labels) 
  * @param labels 
  */ 
 public void setLabels(List<String> labels) { 
  setLabels((String[]) labels.toArray()); 
 } 
  
 /** 
  *   labels 
  * @param labels 
  */ 
 public void setLabels(String[] labels) { 
  mLabels = labels; 
  mLocations = new int[labels.length][2]; 
  mFontSizes = new int[labels.length]; 
  mDirections = new int[labels.length][2]; 
  mTextWidthAndHeight = new int[labels.length][2]; 
   
  mSpeeds = new int[labels.length][2]; 
  for(int speed[] : mSpeeds) { 
   speed[0] = speed[1] = 1; 
  } 
   
  requestLayout(); 
 } 
  
 /** 
  *        
  * @param colorSchema 
  */ 
 public void setColorSchema(int[] colorSchema) { 
  mColorSchema = colorSchema; 
 } 
  
 /** 
  *     item x/y   
  * <p> 
  * speeds.length > labels.length       
  * <p> 
  * speeds.length < labels.length       
  * 
  * @param speeds 
  */ 
 public void setSpeeds(int[][] speeds) { 
  mSpeeds = speeds; 
 } 
  
 /** 
  *   item        
  * @param l 
  */ 
 public void setOnItemClickListener(OnItemClickListener l) { 
  getParent().requestDisallowInterceptTouchEvent(true); 
  mListener = l; 
 } 
  
 /** 
  * item        
  */ 
 public interface OnItemClickListener { 
  public void onItemClick(int index, String label); 
 } 
} 
올 라 와 서 상수 4 개 를 만 들 었 는데 뭐 하 는 거 야?각 아 이 템 의 방향 을 판단 해 야 합 니 다.특정한 경계 에 이 르 렀 을 때 아 이 템 은 반대 방향 으로 이동 해 야 하기 때 문 입 니 다.
두 번 째 구조 방법 에서 사용자 정의 속성 을 얻 었 고 초기 화 된 Paint 도 있 습 니 다.
계속 onLayout 를 보 세 요.사실 onLayout 는 아무것도 하지 않 았 습 니 다.init 방법 만 호출 했 습 니 다.init 방법 을 보 세 요.

/** 
 *      、  、label   
 *       
 */ 
private void init() { 
 if(!hasContents()) { 
  return; 
 } 
   
 int minX = getPaddingLeft(); 
 int minY = getPaddingTop(); 
 int maxX = getMeasuredWidth() - getPaddingRight(); 
 int maxY = getMeasuredHeight() - getPaddingBottom(); 
   
 Rect textBounds = new Rect(); 
   
 for (int i = 0; i < mLabels.length; i++) { 
  int[] location = new int[2]; 
  location[0] = minX + (int) (Math.random() * maxX); 
  location[1] = minY + (int) (Math.random() * maxY); 
    
  mLocations[i] = location; 
  mFontSizes[i] = 15 + (int) (Math.random() * 30); 
  mDirections[i][0] = Math.random() > 0.5 ? DIRECTION_RIGHT : DIRECTION_LEFT; 
  mDirections[i][1] = Math.random() > 0.5 ? DIRECTION_BOTTOM : DIRECITON_TOP; 
    
  mPaint.setTextSize(mFontSizes[i]); 
  mPaint.getTextBounds(mLabels[i], 0, mLabels[i].length(), textBounds); 
  mTextWidthAndHeight[i][0] = textBounds.width(); 
  mTextWidthAndHeight[i][1] = textBounds.height(); 
 } 
   
 if(!isStatic) run(); 
} 
init 방법 에서 올 라 와 서 탭 이 설정 되 어 있 는 지 여 부 를 판단 하고 설정 되 어 있 지 않 으 면 바로 돌아 가 는 것 이 편리 합 니 다.
10~13 줄 의 목적 은 아 이 템 이 이 view 에서 이동 하 는 상하 좌우 경 계 를 가 져 오 는 것 입 니 다.아 이 템 은 전체 view 에서 이동 해 야 하기 때문에 view 의 경 계 를 초과 해 서 는 안 됩 니 다.
17 줄,모든 탭 을 옮 겨 다 니 는 for 순환 을 시작 합 니 다.
18~20 줄 은 무 작위 로 한 위 치 를 초기 화 하 는 것 이기 때문에 우리 의 라벨 이 매번 나타 나 는 위 치 는 무 작위 이 고 규칙 적 이지 않 지만 다음 이동 은 규칙 적 이 므 로 여기저기 뛰 어 다 닐 수 는 없 잖 아 요.
이 어 22 줄 은 이 위 치 를 저장 했다.왜냐하면 우 리 는 아래 에서 이 위 치 를 계속 수정 해 야 하기 때문이다.
23 줄 은 글꼴 크기,24,25 줄 을 무 작위 로 하고 이 탭 x/y 의 초기 방향 을 무 작위 로 합 니 다.
27 줄,현재 탭 의 글꼴 크기 를 설정 합 니 다.28 줄 은 탭 의 너비 와 높이 를 가 져 오고 아래 에 2 차원 배열 에 저 장 됩 니 다.왜 2 차원 배열 입 니까?우 리 는 여러 개의 탭 이 있 습 니 다.모든 탭 은 너비 와 높이 를 저장 해 야 합 니 다.
마지막 으로,만약 우리 가 표시 하지 않 은 성명 labelview 가 정지 되 어 있다 면,run 방법 을 호출 하 십시오.
코드 를 계속 따라 가서 run 방법의 내장 을 보 세 요.

/** 
 *             postInvalidate 
 */ 
private void run() { 
 if(mThread != null && mThread.isAlive()) { 
  return; 
 } 
  
 mThread = new Thread(mStartRunning); 
 mThread.start(); 
} 
5~7 줄,만약 에 스 레 드 가 열 렸 다 면 직접 return 은 여러 스 레 드 가 공존 하 는 것 을 방지 합 니 다.그러면 결 과 는 라벨 이 점점 빨 라 지 는 것 입 니 다.
9,10 줄,스 레 드 를 시작 하고 mStartRunning 의 Runnable 인자 가 있 습 니 다.
그럼 이 Runnable 을 계속 보 겠 습 니 다.

private Runnable mStartRunning = new Runnable() { 
 @Override 
 public void run() { 
  for(;;) { 
   SystemClock.sleep(100); 
     
   for (int i = 0; i < mLabels.length; i++) { 
    if (mLocations[i][0] <= getPaddingLeft()) { 
     mDirections[i][0] = DIRECTION_RIGHT; 
    } 
      
    if (mLocations[i][0] >= getMeasuredWidth() 
      - getPaddingRight() - mTextWidthAndHeight[i][0]) { 
     mDirections[i][0] = DIRECTION_LEFT; 
    } 
    
    if(mLocations[i][1] <= getPaddingTop() + mTextWidthAndHeight[i][1]) { 
     mDirections[i][1] = DIRECTION_BOTTOM; 
    } 
      
    if (mLocations[i][1] >= getMeasuredHeight() - getPaddingBottom()) { 
     mDirections[i][1] = DIRECITON_TOP; 
    } 
      
    int xSpeed = 1; 
    int ySpeed = 2; 
      
    if(i < mSpeeds.length) { 
     xSpeed = mSpeeds[i][0]; 
     ySpeed = mSpeeds[i][1]; 
    }else { 
     xSpeed = mSpeeds[i-mSpeeds.length][0]; 
     ySpeed = mSpeeds[i-mSpeeds.length][1]; 
    } 
      
    mLocations[i][0] += mDirections[i][0] == DIRECTION_RIGHT ? xSpeed : -xSpeed; 
    mLocations[i][1] += mDirections[i][1] == DIRECTION_BOTTOM ? ySpeed : -ySpeed; 
   } 
     
   postInvalidate(); 
  } 
 } 
}; 
이 Runnable 이 야 말로 태그 클 라 우 드 가 실현 하 는 관건 입 니 다.우 리 는 이 스 레 드 에서 모든 태그 의 위 치 를 수정 하고 view 에 다시 그 리 는 것 을 알 립 니 다.
그리고 run 에서 죽은 순환 을 볼 수 있 습 니 다.그래 야 우리 의 라벨 이 끊임없이 이동 할 수 있 습 니 다.그 다음 에 스 레 드 를 100 ms 쉬 게 하 는 것 입 니 다.계속 이동 할 수 는 없 잖 아 요.속도 가 너무 빨 라 도 좋 지 않 고 성능 문제 도 고려 해 야 합 니 다.
다음 일곱 번 째 줄 은 모든 탭,8~23 줄 을 옮 겨 다 니 며 현재 위치 가 특정한 경계 에 이 르 렀 는 지 판단 하고 도착 하면 방향 을 반대 방향 으로 바 꿉 니 다.예 를 들 어 지금 view 의 맨 위 에 이 르 렀 으 면 이 탭 은 아래로 이동 해 야 합 니 다.
25,26 줄,x/y 의 속 도 를 기본 으로 합 니 다.왜 기본 이 라 고 합 니까?모든 탭 의 x/y 속 도 는 우리 가 방법 을 통 해 설정 할 수 있 기 때 문 입 니 다.
다음 28~34 줄 은 하나의 판단 을 했다.대체적으로 설정 한 속도 가 현재 탭 s 에 있 는 위치 보다 많 으 면 해당 하 는 위치 속 도 를 찾 아 라.그렇지 않 으 면 앞에서 속 도 를 다시 얻 는 것 이다.
36,37 줄 은 x/y 의 방향 에 따라 현재 탭 의 좌 표를 수정 하 는 것 이다.
마지막 으로 post Invaidate()를 호출 하여 view 에 게 화면 을 새로 고침 하 라 고 알 렸 습 니 다.여 기 는 post Invaidate()를 사용 합 니 다.우 리 는 스 레 드 에서 호출 되 었 기 때문에 기억 하 십시오.
post Invaidate()후 에는 반드시 onDraw()로 가서 이 라벨 을 그 려 야 합 니 다.그러면 onDraw 를 보 겠 습 니 다.

@Override 
protected void onDraw(Canvas canvas) { 
 if(!hasContents()) { 
  return; 
 } 
   
 for (int i = 0; i < mLabels.length; i++) { 
  mPaint.setTextSize(mFontSizes[i]); 
    
  if(i < mColorSchema.length) mPaint.setColor(mColorSchema[i]); 
  else mPaint.setColor(mColorSchema[i-mColorSchema.length]); 
    
  canvas.drawText(mLabels[i], mLocations[i][0], mLocations[i][1], mPaint); 
 } 
} 
올 라 와 서 판단 해 봤 는데 태그 가 설정 되 어 있 지 않 으 면 바로 돌아 갑 니 다.탭 이 있다 면 모든 탭 을 옮 겨 다 니 며 해당 하 는 글꼴 크기 를 설정 하 십시오.기억 하 십 니까?초기 화 할 때 모든 탭 의 글꼴 크기 를 무 작위 로 설정 한 다음 에 이 탭 의 색상 을 설정 합 니 다.if else 원리 와 설정 속도 가 같 습 니 다.가장 중요 한 것 은 바로 아래 입 니 다.canvas.draw Text()를 호출 하여 이 탭 을 화면 에 그 렸 습 니 다.mLocations 에 서 는 모든 탭 의 위 치 를 저장 하 였 습 니 다.그것 도 스 레 드 에서 이 위 치 를 계속 수정 하 는 거 야.
여기까지,사실 우리 의 LabelView 는 움 직 일 수 있 지만,그 몇 개의 탭,속도,색깔 을 설정 하 는 방법 은 또 말 할 수 있다.사실 간단 해 요.한번 보 세 요.

/** 
 *   labels 
 * @see setLabels(String[] labels) 
 * @param labels 
 */ 
public void setLabels(List<String> labels) { 
 setLabels((String[]) labels.toArray()); 
} 
  
/** 
 *   labels 
 * @param labels 
 */ 
public void setLabels(String[] labels) { 
 mLabels = labels; 
 mLocations = new int[labels.length][2]; 
 mFontSizes = new int[labels.length]; 
 mDirections = new int[labels.length][2]; 
 mTextWidthAndHeight = new int[labels.length][2]; 
   
 mSpeeds = new int[labels.length][2]; 
 for(int speed[] : mSpeeds) { 
  speed[0] = speed[1] = 1; 
 } 
   
 requestLayout(); 
} 
  
/** 
 *        
 * @param colorSchema 
 */ 
public void setColorSchema(int[] colorSchema) { 
 mColorSchema = colorSchema; 
} 
  
/** 
 *     item x/y   
 * <p> 
 * speeds.length > labels.length       
 * <p> 
 * speeds.length < labels.length       
 * 
 * @param speeds 
 */ 
public void setSpeeds(int[][] speeds) { 
 mSpeeds = speeds; 
} 
이 몇 개의 알 이 아 픈 방법 중 유일 하 게 말 할 수 있 는 것 은 setLabels(String[]labels)이다.왜냐하면 이 방법 에서 일 도 좀 했 기 때문이다.자세히 살 펴 보면 이 방법 은 태그 s 를 설정 한 것 을 제외 하고 몇 개의 배열 을 초기 화 하 는 것 입 니 다.무엇 을 표시 하 는 지 잘 알 것 입 니 다.그리고 여기 서 우 리 는 기본 속 도 를 1 로 초기 화 했 습 니 다.
처음 프 리 젠 테 이 션 을 하 러 올 라 왔 을 때 LabelView 는 아 이 템 을 클릭 할 수 있 었 는데 어떻게 했 을 까?일반적인 onClick 은 안 됩 니 다.우 리 는 클릭 한 x/y 좌 표를 모 르 기 때문에 onTouch Event 를 통 해 얻 을 수 밖 에 없습니다.

@Override 
public boolean onTouchEvent(MotionEvent ev) { 
 switch (ev.getAction()) { 
 case MotionEvent.ACTION_DOWN: 
  mDownX = (int) ev.getX(); 
  mDownY = (int) ev.getY(); 
  mDownIndex = getClickIndex(); 
  break; 
 case MotionEvent.ACTION_UP: 
  int nowX = (int) ev.getX(); 
  int nowY = (int) ev.getY(); 
  if (nowX - mDownX < mTouchSlop && nowY - mDownY < mTouchSlop 
    && mDownIndex != -1 && mListener != null) { 
   mListener.onItemClick(mDownIndex, mLabels[mDownIndex]); 
  } 
    
  mDownX = mDownY = mDownIndex = -1; 
  break; 
 } 
   
 return true; 
} 
onTouch 에서 우 리 는 다운 과 업 이벤트 에 만 관심 을 가 졌 습 니 다.한 번 클릭 하면 다운 과 업 의 조합 이 니까 요.
down 에서 우 리 는 현재 이벤트 가 발생 한 x/y 좌 표를 얻 었 고 현재 클릭 한 item 을 얻 었 습 니 다.현 재 는 getClickIndex()방법 으로 얻 었 습 니 다.이 방법 은 잠시 만 기 다 려 주 십시오.다시 한 번 up 을 살 펴 보 겠 습 니 다.up 에서 우 리 는 현재 의 x/y 와 down 에 있 을 때의 x/y 를 비교 합 니 다.만약 에 이 두 가지 거리 가 시스템 이 생각 하 는 최소 미끄럼 거리 보다 작 아야 클릭 이 유효 하 다 는 것 을 설명 할 수 있 습 니 다.만약 에 down 이후 에 긴 선 을 당 겼 다 면 up 은 효과 적 인 클릭 이 아 닐 것 입 니 다.물론 클릭 이 효과 가 있 으 면 모든 것 을 설명 할 수 없습니다.명중 라벨 만 있 습 니 다.그래서 mDownIndex 가 유효한 값 인지 판단 하고 ItemClick 을 설정 하면 되 돌려 줍 니 다.
그럼 mDownIndex 는 어떻게 얻 은 거 예요?getClickIndex()를 살 펴 보 겠 습 니 다.

/** 
 *        label    
 * @return label   ,      -1 
 */ 
private int getClickIndex() { 
 Rect downRect = new Rect(); 
 Rect locationRect = new Rect(); 
 for(int i=0;i<mLocations.length;i++) { 
  downRect.set(mDownX - mTextWidthAndHeight[i][0], mDownY 
    - mTextWidthAndHeight[i][1], mDownX 
    + mTextWidthAndHeight[i][0], mDownY 
    + mTextWidthAndHeight[i][1]); 
    
  locationRect.set(mLocations[i][0], mLocations[i][1], 
    mLocations[i][0] + mTextWidthAndHeight[i][0], 
    mLocations[i][1] + mTextWidthAndHeight[i][1]); 
    
  if(locationRect.intersect(downRect)) { 
   return i; 
  } 
 } 
 return -1; 
} 
먼저 Rect 두 개 를 정 의 했 습 니 다.하 나 는 클릭 한 rect 이 고,다른 하 나 는 탭 의 rect 입 니 다.그리고 저 장 된 최신 탭 의 위 치 를 옮 겨 다 니 며 순환 중 에 Rect.set()방법 으로 down 의 사각형 상하 좌우 와 현재 탭 의 상하 왼쪽 오른쪽 을 각각 설정 한 다음 Rect.intersect()방법 으로 이 두 사각형 이 교차 하 는 지 여 부 를 판단 합 니 다.교차 집합 이 있 으 면 이 탭 을 클릭 했다 는 것 을 증명 합 니 다.이 탭 이 탭 s 에 있 는 위 치 를 되 돌려 줍 니 다.만약 에 되 돌아 오지 않 았 다 면-1 은 가장귀 가 어 지 러 웠 음 을 나타 냅 니 다!
자,여기까지.모든 LabelView 가 다 되 었 으 니 어서 소스 코드 를 다운로드 해서 체험 해 보 세 요.물론 완벽 하 지 는 않 습 니 다.완벽 한 해결 방안 은 사용 할 때 해결 하 겠 습 니 다.헤헤,어쨌든 우 리 는 이미 생각 이 있 습 니 다.
아,맞다.아직 원본 다운로드 주 소 를 알려 주지 않 았 어여기,이곳
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기