国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android自定義TipView仿QQ長按后的提示窗口

2019-10-22 18:11:08
字體:
來源:轉載
供稿:網友

自定義view--TipView

TipView其實就是類似QQ長按消息彈出來的橫放的提示框。

通過看書和參考各位大神的博客(再次對大神表示恭敬),我用了一下午時間寫完了這么一個view。

先來看圖:

Android,TipView,提示窗口,長按

Android,TipView,提示窗口,長按

Android,TipView,提示窗口,長按

1 自定義TipView思路

1 首先我們考慮是繼承View還是ViewGroup

其實TipView直觀看更像是一個group,里面有子view。但其實我們并不需要繼承ViewGroup,因為我們不用像LinearLayout那樣在布局文件里面去添加子view,而且TipView的item我們用文字就好。如果繼承于Group我們還要考慮onLayout的問題,為了簡單我直接繼承自View。

2 重寫方法

TipView要像PopupWindow、Dialog一樣顯示在Activity上而不是添加到父容器中,原因是如果創建后添加到父容器中去托管的話,父容器的布局規則會影響我們TipView的顯示效果。所以我們要使用WindowManager來把TipView添加到外層布局,并且要充滿屏幕,i原因為我們要點擊tem之外的地方使TipView消失。所以view大小是固定充滿屏幕的,不需要重寫onMeasure。
需要重寫onDraw來繪制view。

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 Builder模式創建

 

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 会理县| 娱乐| 渭源县| 红河县| 商洛市| 达日县| 宜丰县| 收藏| 杨浦区| 中江县| 手机| 波密县| 麦盖提县| 扎赉特旗| 长春市| 左云县| 安龙县| 鹤壁市| 高青县| 房产| 抚远县| 平潭县| 深州市| 团风县| 油尖旺区| 星座| 屯门区| 鹤庆县| 渭南市| 兴宁市| 察隅县| 徐闻县| 陇南市| 泗阳县| 昌黎县| 盐边县| 松江区| 青州市| 德钦县| 绵阳市| 夹江县|