안 드 로 이 드 사용자 정의 TipView QQ 길 이 를 본 떠 서 누 른 알림 창

사용자 정의 view--TipView
TipView 는 사실 QQ 길이 가 메시지 에 따라 튕 겨 나 오 는 가로로 놓 인 알림 상자 와 유사 합 니 다.
책 을 읽 고 여러분 의 블 로 그 를 참고 하여 오후 내 내 이 뷰 를 다 썼 습 니 다.
먼저 그림 보기:



1 사용자 정의 TipView 사고방식
1 우선 뷰 를 계승 할 지 뷰 그룹 을 계승 할 지
사실 TipView 는 직관 적 으로 보면 그룹 같 고 그 안에 하위 view 가 있다.그러나 사실 우 리 는 View Group 을 계승 할 필요 가 없습니다.LinearLayout 처럼 레이아웃 파일 에 하위 view 를 추가 하지 않 아 도 되 고 TipView 의 item 은 문자 로 하면 됩 니 다.Group 에 물 려 받 으 면 onLayout 문 제 를 고려 해 야 합 니 다.간단 하기 위해 서 는 제 가 직접 View 를 물 려 받 겠 습 니 다.
2 재 작성 방법
TipView 는 부모 용기 에 추가 하 는 대신 PopupWindow,Dialog 처럼 Activity 에 표시 해 야 합 니 다.생 성 후 부모 용기 에 추가 하여 위탁 관리 하면 부모 용기 의 레이아웃 규칙 이 우리 TipView 의 디 스 플레이 효과 에 영향 을 줄 수 있 기 때 문 입 니 다.그래서 저 희 는 Window Manager 를 사용 하여 TipView 를 외부 레이아웃 에 추가 하고 화면 을 가득 채 워 야 합 니 다.i 이 유 는 tem 이외 의 곳 을 클릭 하여 TipView 를 사라 지게 해 야 하기 때 문 입 니 다.그래서 view 크기 는 화면 에 고정 되 어 있 습 니 다.onMeasure 를 다시 쓸 필요 가 없습니다.
view 를 그 리 려 면 onDraw 를 다시 써 야 합 니 다.
3 표시 위치
TipView 는 주로 두 부분 으로 나 뉘 는데 일 부 는 삼각 표 이 고 일 부 는 원 각 을 가 진 주체 이다.
우리 가 클릭 한 후에 삼각 표 의 정점 은 항상 클릭 위치 위 에서 일정한 거리(정점 이 클릭 위치 에 위치 하면 손가락 이 일부 삼각형 을 가리 고 사용자 체험 도가 좋 지 않 음)에 있 으 며 주 체 는 화면 좌우 경계 와 부 딪 히 지 말고 Toolbar 를 가 릴 때 아래로 그립 니 다.
2 정의 변수

public static final int TOP = 0;//         
  public static final int DOWN = 1;//...  ...

  private int mItemWidth;//item 
  private int mItemHeight;//item 
  private int mTriaHeight;//     
  private int mHalfTriaWidth;//     
  private int mTriaAcme;//     
  private int mTriaItemBorder;//     
  private int realLeft;//       
  private int marginSide;//        ,           
  private int mSeparateLineColor = Color.WHITE;
  private int mTextSize;//       
  private int mTextColor;//       

  private int mItemSeparation;//     ;
  private int mRadius;//  
  private List<TextItem> items;//  item   
  private List<Rect> mItemRectList = new ArrayList<>(); //       
  private Paint mPaint;//  
  private Paint mSeparationPaint;//     
  private Paint mSPaint;//     
  private Path mPath;//  
  private int x, y;//     
  private ViewGroup viewRoot;//   
  private int location = TOP;//    
  private int choose = -1;//   item
  private int mToolbarBottom;//Toolbar        
  private WindowManager windowManager;
  private WindowManager.LayoutParams layoutParams;//windowManger     ,   Dialog   Activity  ,        group
  private onItemCilckLinener itemCilckLinener;
  private Context context = null;
3 구조 함수 및 초기 화 방법

private MyTipView(Context context, int x, int y, ViewGroup viewRoot, List<TextItem> items) {
    super(context);
    this.viewRoot = viewRoot;
    this.context = context;
    this.x = x;
    this.y = y;
    this.items = items;
    windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    layoutParams = new WindowManager.LayoutParams();
    layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;//    
    layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;//    
    //  LayoutParams   
    layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;// Type              ,           
    layoutParams.format = PixelFormat.TRANSLUCENT;//                  
    //layoutParams.token = viewRoot.getWindowToken();//  Token
    int[] location = new int[2];
    viewRoot.getLocationInWindow(location);//             
    viewRoot.getLocationOnScreen(location);//             
    mToolbarBottom = location[1];//[0] x   ,[1]y 
    windowManager.addView(this, layoutParams);
    init();
    initView();
  }

  //     
  private void init() {
    mPaint = new Paint();
    mSPaint = new Paint();
    mPath = new Path();
    mSeparationPaint = new Paint();
    mSeparationPaint.setStyle(Paint.Style.FILL);
    mPaint.setAntiAlias(true);
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setTextSize(Sp2Px(14));
    mPaint.setColor(Color.BLACK);
    mSPaint.setAntiAlias(true);
    mSPaint.setStyle(Paint.Style.FILL);
    mSPaint.setColor(Color.BLACK);
    //    
    mItemWidth = Dp2Px(50);
    mItemHeight = Dp2Px(48);
    mTriaHeight = Dp2Px(10);//     
    mHalfTriaWidth = Dp2Px(6);//     
    mTriaAcme = Dp2Px(6);//     
    marginSide = Dp2Px(4);//    
    mItemSeparation = Dp2Px(1);//     ;
    mRadius = Dp2Px(6);//  
    mTextColor = Color.WHITE;
    mTextSize = Sp2Px(14);
  }
4 삼각 정점 위치 계산

private void initView() {
    int count = items.size();
    int width = count * mItemWidth + mItemSeparation * (count - 1);
    int mScreenWidth = getResources().getDisplayMetrics().widthPixels;
    if (y - mToolbarBottom < (mItemHeight + mTriaHeight + mTriaAcme)) {
      location = DOWN;//    
      mTriaAcme += y;//      y  ;
      mTriaItemBorder = mTriaAcme + mTriaHeight;//        y
    } else {
      location = TOP;
      mTriaAcme = y - mTriaAcme;//      y  
      mTriaItemBorder = mTriaAcme - mTriaHeight;//        y 
    }
    if (x < (width / 2 + marginSide)) {
      realLeft = marginSide;//             ,     
    } else if ((mScreenWidth - x) < (width / 2 + marginSide)) {
      realLeft = mScreenWidth - marginSide - width;//             ,     
    } else {
      realLeft = x - width / 2;//             ,      
    }
  }
5 배경 투명 설정

private void drawBackground(Canvas canvas) {
    canvas.drawColor(Color.TRANSPARENT);
  }
6 삼각형 그리 기

private void drawTop(Canvas canvas) {
    //    
    mPath.reset();
    mPath.moveTo(x, mTriaAcme);
    mPath.lineTo(x - mHalfTriaWidth, mTriaAcme - mTriaHeight);
    mPath.lineTo(x + mHalfTriaWidth, mTriaAcme - mTriaHeight);
    canvas.drawPath(mPath, mSPaint);
    MyDraw(canvas, mTriaItemBorder - mItemHeight);
  }

  private void drawDown(Canvas canvas) {
    //    
    mPath.reset();//    
    mPath.moveTo(x, mTriaAcme);
    mPath.lineTo(x - mHalfTriaWidth, mTriaAcme + mTriaHeight);
    mPath.lineTo(x + mHalfTriaWidth, mTriaAcme + mTriaHeight);
    canvas.drawPath(mPath, mSPaint);
    //    
    MyDraw(canvas, mTriaItemBorder);
  }
7 사각형 그리 기
그림 을 그 릴 때 첫 번 째 와 마지막 사각형 이 원 각 을 가지 고 있 기 때문에 단독으로 그립 니 다.

private void MyDraw(Canvas canvas, int t) {
    //  item
    int count = items.size();
    int width = (count - 1) * mItemSeparation + count * mItemWidth;
    int l = realLeft + mItemWidth + mItemSeparation;
    mItemRectList.clear();
    for (int i = 0; i < items.size(); i++) {
      if (choose == i) {//       ,    
        mPaint.setColor(Color.DKGRAY);
      } else {
        mPaint.setColor(Color.BLACK);
      }
      if (i == 0) {//         item
        mPath.reset();
        mPath.moveTo(realLeft + mItemWidth, t);
        mPath.lineTo(realLeft + mRadius, t);
        mPath.quadTo(realLeft, t, realLeft, t + mRadius);
        mPath.lineTo(realLeft, t + mItemHeight - mRadius);
        mPath.quadTo(realLeft, t + mItemHeight, realLeft + mRadius, mItemHeight + t);
        mPath.lineTo(realLeft + mItemWidth, t + mItemHeight);
        canvas.drawPath(mPath, mPaint);
        mSeparationPaint.setColor(mSeparateLineColor);
        canvas.drawLine(realLeft + mItemWidth, t, realLeft + mItemWidth,
            t + mItemHeight, mSeparationPaint);
      } else if (i == (items.size() - 1)) {//      
        mPath.reset();
        mPath.rMoveTo(realLeft + width - mItemWidth, t);
        mPath.lineTo(realLeft + width - mRadius, t);
        mPath.quadTo(realLeft + width, t, realLeft + width, t + mRadius);
        mPath.lineTo(realLeft + width, t + mItemHeight - mRadius);
        mPath.quadTo(realLeft + width, t + mItemHeight, realLeft + width - mRadius, t + mItemHeight);
        mPath.lineTo(realLeft + width - mItemWidth, t + mItemHeight);
        canvas.drawPath(mPath, mPaint);
      } else {//          
        mPath.reset();
        mPath.moveTo(l, t);
        mPath.lineTo(l + mItemWidth, t);
        mPath.lineTo(l + mItemWidth, t + mItemHeight);
        mPath.lineTo(l, t + mItemHeight);
        canvas.drawPath(mPath, mPaint);
        canvas.drawLine(l + mItemWidth, t, l + mItemWidth, t + mItemHeight,
            mSeparationPaint);
        l += mItemWidth + mItemSeparation;
      }
      mItemRectList.add(new Rect(realLeft + i * (mItemSeparation + mItemWidth), t, realLeft + i * (mItemSeparation + mItemWidth) + mItemWidth, t + mItemHeight));
    }
  }
마지막 줄 코드
mItemRectList.add(new Rect(realLeft + i * (mItemSeparation + mItemWidth), t, realLeft + i * (mItemSeparation + mItemWidth) + mItemWidth, t + mItemHeight));
하나의 List 로 Rect(사각형)를 저장 합 니 다.이 사각형 들 은 모든 item 의 사각형 에 대응 하지만 그 려 지지 않 았 습 니 다.저장 만 합 니 다.사각형 은 문 자 를 그 릴 때 텍스트 거 리 를 제공 하기 위해 사 용 됩 니 다.
8 텍스트 그리 기

private void drawTitle(Canvas canvas) {
    for (int i = 0; i < items.size(); i++) {
      Rect rect = mItemRectList.get(i);//      
      //mPaint.setColor(Color.WHITE);
      Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
      p.setAntiAlias(true);
      p.setStrokeWidth(3);
      int s = Dp2Px(items.get(i).getTextSize());
      p.setTextSize(mTextSize);
      if (s != 0)//   TextItem    size,      size
        p.setTextSize(s);
      p.setColor(mTextColor);
      Paint.FontMetricsInt fontMetricsInt = p.getFontMetricsInt();
      p.setTextAlign(Paint.Align.CENTER);
      int baseline = (rect.bottom + rect.top - fontMetricsInt.bottom - fontMetricsInt.top) / 2;//    ,    
      canvas.drawText(items.get(i).getTitle(), rect.centerX(), baseline, p);
    }
  }
9 클릭 변색 및 클릭 이벤트 구현

@Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        for (int i = 0; i < items.size(); i++) {
          if (itemCilckLinener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {
            choose = i;//    item  
            Rect rect = mItemRectList.get(i);
            postInvalidate(rect.left, rect.top, rect.right, rect.bottom);//    
            return true;
          }
        }
        removeView();//  item    
        return false;
      case MotionEvent.ACTION_UP:
        for (int i = 0; i < items.size(); i++) {
          if (itemCilckLinener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {
            if (i == choose) {// down item      
              itemCilckLinener.onItemCilck(items.get(i).getTitle(), i);//      
              removeView();
              return true;
            }
          } else {//      item,     
            postInvalidate();//    
          }
        }
        choose = -1;//  
        return false;
    }
    return false;
  }
 /**
   *             
   *
   * @param pointF
   * @param targetRect
   * @return
   */
  private boolean isPointInRect(PointF pointF, Rect targetRect) {
    if (pointF.x < targetRect.left) {
      return false;
    }
    if (pointF.x > targetRect.right) {
      return false;
    }
    if (pointF.y < targetRect.top) {
      return false;
    }
    if (pointF.y > targetRect.bottom) {
      return false;
    }
    return true;
  }
10 빌 더 모드 생 성
 

public static class Builder {
    private List<TextItem> items = new ArrayList<>();
    private int x = 0, y = 0;
    private Context context;
    private ViewGroup viewRoot;
    private onItemCilckLinener itemCilckLinener;
    private int mRadius;

    public Builder(Context context, ViewGroup viewRoot) {
      this.context = context;
      this.viewRoot = viewRoot;
    }
    public Builder addItem(TextItem item) {
      items.add(item);
      return this;
    }
    public Builder setmRadius(int radius) {
      mRadius = radius;
      return this;
    }
    public Builder setxAndy(int x, int y) {
      this.x = x;
      this.y = y;
      return this;
    }
    public Builder setOnItemClickLinener(onItemCilckLinener itemClickLinener) {
      this.itemCilckLinener = itemClickLinener;
      return this;
    }
    public MyTipView create() {
      if (items.size() == 0) {
        try {
          throw new Exception("item count is 0");
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      MyTipView myTipView = new MyTipView(context, x, y, viewRoot, items);
      myTipView.setItemCilckLinener(itemCilckLinener);
      if (mRadius != 0)
        myTipView.setRadius(mRadius);
      return myTipView;
    }
  }

11 item

//TipView item
  public static class TextItem {
    private String title;
    private int textSize;
    private int textColor = Color.WHITE;

    public TextItem(String title) {
      this.title = title;
    }
    public TextItem(String title, int textSize) {
      this.title = title;
      this.textSize = textSize;
    }
    public TextItem(String title, int textSize, int textColor) {
      this.title = title;
      this.textSize = textSize;
      this.textColor = textColor;
    }
    public String getTitle() {
      return title;
    }
    public void setTitle(String title) {
      this.title = title;
    }
    public int getTextSize() {
      return textSize;
    }
    public void setTextSize(int textSize) {
      this.textSize = textSize;
    }
    public int getTextColor() {
      return textColor;
    }
    public void setTextColor(int textColor) {
      this.textColor = textColor;
    }
  }

12 사용 예시

MyTipView.Builder builder = new MyTipView.Builder(this, linearLayout);
    builder.addItem(new MyTipView.TextItem("1"))
        .addItem(new MyTipView.TextItem("2"))
        .addItem(new MyTipView.TextItem("3"))
        .addItem(new MyTipView.TextItem("4"))
        .setxAndy((int) x, (int) y)
        .setOnItemClickLinener(new MyTipView.onItemCilckLinener() {
          @Override
          public void onItemCilck(String title, int i) {
            Toast.makeText(MainActivity.this, title, Toast.LENGTH_SHORT).show();
          }
        })
        .create();
13 소스 코드
https://github.com/liujiakuoyx/learn/blob/master/MyTipView.java
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기