今天我接著站在了巨人的肩膀上了!因為上次我參考大神利用 Path 實現了點九圖效果,附上我上次講解連結: juejin.im/post/58c3b8… .這一次,我將完成上次說的實現點選toolbar按鈕彈出選單效果,當然還是利用 Path 來完成這個效果.如果想看巨人的鉅作,請點選: juejin.im/post/5865f4… ,我此次僅僅是將大神的點九圖更換為一個由Path完成的效果而已.
首先,我們還是看下我完成的結果吧!
嘿嘿,和大神的一樣哈!是的,我只是改了背景圖而已.這樣我們就可以隨便刷不要UI哥幫忙了,而且那個三角凸起可以 左右位置調整 哦!
首先還是看下MainActivity的佈局吧
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.jooyerbubblemenu.MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/colorPrimary">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:text="@string/app_name"
android:textColor="@android:color/white"
android:textSize="20sp"
android:layout_centerVertical="true"/>
<ImageView
android:id="@+id/more"
android:layout_width="50dp"
android:layout_height="match_parent"
android:src="@mipmap/common_forward_normal"
android:scaleType="center"
android:layout_alignParentRight="true"/>
</RelativeLayout>
</LinearLayout>複製程式碼
這個就不說啥了,接著,來重點了,看 Recyclerview 了,因為大神用的是這個控制元件,那我只是給這個控制元件換了個衣服!
package com.jooyerbubblemenu;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
/**
* Created by Jooyer on 2017/3/19
*/
public class JooyerBubbleRecyclerView extends RecyclerView{
private JooyerBubbleDrawable mBubbleDrawable;
private float mArrowWidth;
private float mArrowHeight;
private float mRadius;
private float mArrowOffset;
private int mBubbleColor;
private JooyerBubbleDrawable.ArrowDirection mArrowDirection;
private boolean mArrowCenter;
public JooyerBubbleRecyclerView(Context context) {
this(context,null);
}
public JooyerBubbleRecyclerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public JooyerBubbleRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context,attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(R.styleable.JooyerBubbleRecyclerView);
mArrowWidth = array.getDimension(R.styleable.JooyerBubbleRecyclerView_jooyer_bubble_arrow_width,
JooyerBubbleDrawable.Builder.DEFAULT_ARROW_WIDTH);
mArrowHeight = array.getDimension(R.styleable.JooyerBubbleRecyclerView_jooyer_bubble_arrow_height,
JooyerBubbleDrawable.Builder.DEFAULT_ARROW_HEIGHT);
mRadius = array.getDimension(R.styleable.JooyerBubbleRecyclerView_jooyer_bubble_arrow_radius,
JooyerBubbleDrawable.Builder.DEFAULT_RADIUS);
int location = array.getInt(R.styleable.JooyerBubbleRecyclerView_jooyer_bubble_arrow_direction, 0);
mArrowDirection = JooyerBubbleDrawable.ArrowDirection.mapIntToValue(location);
mArrowOffset = array.getDimension(R.styleable.JooyerBubbleRecyclerView_jooyer_bubble_arrow_offset,
JooyerBubbleDrawable.Builder.DEFAULT_ARROW_OFFSET);
mBubbleColor = array.getColor(R.styleable.JooyerBubbleRecyclerView_jooyer_bubble_arrow_color,
JooyerBubbleDrawable.Builder.DEFAULT_BUBBLE_COLOR);
mArrowCenter = array.getBoolean(R.styleable.JooyerBubbleRecyclerView_jooyer_bubble_arrow_center,false);
array.recycle();
setPadding();
}
private void setPadding() {
int left = getPaddingLeft();
int top = getPaddingTop();
int right = getPaddingRight();
int bottom = getPaddingBottom();
switch (mArrowDirection){
case LEFT:
left +=mArrowWidth;
break;
case TOP:
top += mArrowHeight;
break;
case RIGHT:
right += mArrowWidth;
break;
case BOTTOM:
bottom +=mArrowHeight;
break;
}
setPadding(left,top,right,bottom);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w >0 || h > 0)
setUp(w,h);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setUp(getWidth(),getHeight());
}
@Override
public void onDraw(Canvas c) {
if (null != mBubbleDrawable){
mBubbleDrawable.draw(c);
}
super.onDraw(c);
}
private void setUp(int width,int height){
setUp(0,0,width,height);
}
public void setUp(int left,int top,int right,int bottom){
mBubbleDrawable = new JooyerBubbleDrawable.Builder()
.rect(new RectF(left,top,right,bottom))
.arrowWidth(mArrowWidth)
.arrowHeight(mArrowHeight)
.arrowOffset(mArrowOffset)
.arrowCenter(mArrowCenter)
.arrowDirection(mArrowDirection)
.radius(mRadius)
.bubbleColor(mBubbleColor)
.build();
}
public void setArrowOffset(float offset){
mArrowOffset = offset;
}
}複製程式碼
沒有什麼註釋,起始和上一篇文章自定義一樣的,所以我們主要就是熟悉這種方式而已!
我們還是瞅一眼 JooyerBubbleDrawable
package com.jooyerbubblemenu;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.Log;
/**
* Created by Jooyer on 2017/3/11
*/
public class JooyerBubbleDrawable extends Drawable {
private static final String TAG = JooyerBubbleDrawable.class.getSimpleName();
/**
* 儲存座標(自定義控制元件的大小)
*/
private RectF mRect;
/**
* 氣泡的路徑
*/
private Path mPath = new Path();
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/**
* 箭頭寬度
*/
private float mArrowWidth;
/**
* 箭頭寬度
*/
private float mArrowHeight;
/**
* 圓弧半徑
*/
private float mRadius;
/**
* 箭頭所在位置偏移量
*/
private float mArrowOffset;
/**
* 氣泡背景色
*/
private int mBubbleColor;
/**
* 三角箭頭所在位置
*/
private ArrowDirection mArrowDirection;
/**
* 箭頭是否居中
*/
private boolean mArrowCenter;
/**
* 重寫此方法,在這裡實現和 自定義控制元件中 onDraw 類似的功能
*/
@Override
public void draw(Canvas canvas) {
mPaint.setColor(mBubbleColor);
setUpPath(mArrowDirection, mPath);
canvas.drawPath(mPath, mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT; //視窗透明化
}
private void setUpPath(ArrowDirection arrowDirection, Path path) {
switch (arrowDirection) {
case LEFT:
setUpLeftPath(mRect, path);
break;
case TOP:
setUpTopPath(mRect, path);
break;
case RIGHT:
setUpRightPath(mRect, path);
break;
case BOTTOM:
setUpBottomPath(mRect,path);
break;
}
}
/**
* 箭頭朝左
*/
private void setUpLeftPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.bottom - rect.top - mArrowWidth) / 2;
path.moveTo(rect.left + mArrowWidth + mRadius, rect.top);
path.lineTo(rect.width() - mRadius, rect.top); // 這裡的rect.width() 是可以使用rect.right
Log.i(TAG, "====setUpLeftPath========" + (rect.width() - mRadius) + "======= : " + (rect.right - mRadius));
path.arcTo(new RectF(rect.right - mRadius, rect.top, rect.right, rect.top + mRadius), 270, 90);
path.lineTo(rect.right, rect.bottom - mRadius);
path.arcTo(new RectF(rect.right - mRadius, mRect.bottom - mRadius, rect.right, rect.bottom), 0, 90);
path.lineTo(rect.left + mArrowWidth + mRadius, rect.bottom);
path.arcTo(new RectF(rect.left + mArrowWidth, rect.bottom - mRadius, rect.left + mArrowWidth + mRadius, rect.bottom), 90, 90);
path.lineTo(rect.left + mArrowWidth, mArrowHeight + mArrowOffset);
path.lineTo(rect.left, mArrowOffset + mArrowHeight / 2);
path.lineTo(rect.left + mArrowWidth, mArrowOffset);
path.lineTo(rect.left + mArrowWidth, rect.top + mRadius);
path.arcTo(new RectF(rect.left + mArrowWidth, mRect.top, rect.left + mArrowWidth + mRadius, rect.top + mRadius), 180, 90);
path.close();
}
/**
* 箭頭朝上
*/
private void setUpTopPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.right - rect.left - mArrowWidth) / 2;
path.moveTo(rect.left + Math.min(mRadius, mArrowOffset), rect.top + mArrowHeight);
path.lineTo(rect.left + mArrowOffset, rect.top + mArrowHeight);
path.lineTo(rect.left + mArrowOffset + mArrowWidth / 2, rect.top);
path.lineTo(rect.left + mArrowOffset + mArrowWidth, rect.top + mArrowHeight);
path.lineTo(rect.right - mRadius, rect.top + mArrowHeight);
path.arcTo(new RectF(rect.right - mRadius, rect.top + mArrowHeight, rect.right, rect.top + mArrowHeight + mRadius), 270, 90);
path.lineTo(rect.right, rect.bottom - mRadius);
path.arcTo(new RectF(rect.right - mRadius, rect.bottom - mRadius, rect.right, rect.bottom), 0, 90);
path.lineTo(rect.left + mRadius, rect.bottom);
path.arcTo(new RectF(rect.left, rect.bottom - mRadius, rect.left + mRadius, rect.bottom), 90, 90);
path.lineTo(rect.left, rect.top + mArrowHeight + mRadius);
path.arcTo(new RectF(rect.left, rect.top + mArrowHeight, rect.left + mRadius, rect.top + mArrowHeight + mRadius), 180, 90);
path.close();
}
/**
* 箭頭朝右
*/
private void setUpRightPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.bottom - rect.top - mArrowWidth) / 2;
path.moveTo(rect.left + mRadius, rect.top);
path.lineTo(rect.right - mRadius - mArrowWidth, rect.top);
path.arcTo(new RectF(rect.right - mArrowWidth - mRadius, rect.top, rect.right - mArrowWidth, rect.top + mRadius), 270, 90);
path.lineTo(rect.right - mArrowWidth, rect.top + mArrowOffset);
path.lineTo(rect.right, rect.top + mArrowOffset + mArrowHeight / 2);
path.lineTo(rect.right - mArrowWidth, rect.top + mArrowOffset + mArrowHeight);
path.lineTo(rect.right - mArrowWidth, rect.bottom - mRadius);
path.arcTo(new RectF(rect.right - mArrowWidth - mRadius, rect.bottom - mRadius, rect.right - mArrowWidth, rect.bottom), 0, 90);
path.lineTo(rect.right - mArrowWidth - mRadius, rect.bottom);
path.arcTo(new RectF(rect.left, rect.bottom - mRadius, rect.left + mRadius, rect.bottom), 90, 90);
path.lineTo(rect.left, rect.top + mRadius);
path.arcTo(new RectF(rect.left, rect.top, rect.left + mRadius, rect.top + mRadius), 180, 90);
path.close();
}
/**
* 箭頭朝下
*/
private void setUpBottomPath(RectF rect, Path path) {
if (mArrowCenter)
mArrowOffset = (rect.right - rect.left - mArrowWidth) / 2;
path.moveTo(rect.left + mRadius, rect.top);
path.lineTo(rect.right - mRadius, rect.top);
path.arcTo(new RectF(rect.right - mRadius, rect.top, rect.right, rect.top + mRadius), 270, 90);
path.lineTo(rect.right, rect.bottom - mArrowHeight - mRadius);
path.arcTo(new RectF(rect.right - mRadius, rect.bottom - mArrowHeight - mRadius, rect.right, rect.bottom - mArrowHeight), 0, 90);
path.lineTo(rect.left + mArrowOffset + mArrowWidth, rect.bottom - mArrowHeight);
path.lineTo(rect.left + mArrowOffset + mArrowWidth / 2, rect.bottom);
path.lineTo(rect.left + mArrowOffset, rect.bottom - mArrowHeight);
path.lineTo(rect.left + mRadius, rect.bottom - mArrowHeight);
path.arcTo(new RectF(rect.left, rect.bottom - mArrowHeight - mRadius, rect.left + mRadius, rect.bottom - mArrowHeight), 90, 90);
path.lineTo(rect.left, rect.top + mRadius);
path.arcTo(new RectF(rect.left, rect.top,rect.left + mRadius,rect.top + mRadius),180,90);
path.close();
}
private JooyerBubbleDrawable(Builder builder) {
this.mRect = builder.mRectF;
this.mRadius = builder.mRadius;
this.mArrowWidth = builder.mArrowWidth;
this.mArrowHeight = builder.mArrowHeight;
this.mArrowOffset = builder.mArrowOffset;
this.mBubbleColor = builder.mBubbleColor;
this.mArrowDirection = builder.mArrowDirection;
this.mArrowCenter = builder.mArrowCenter;
}
/**
* 建造者模式
*/
public static class Builder {
/**
* 箭頭預設寬度
*/
public static float DEFAULT_ARROW_WIDTH = 25;
/**
* 箭頭預設高度
*/
public static float DEFAULT_ARROW_HEIGHT = 25;
/**
* 預設圓角半徑
*/
public static float DEFAULT_RADIUS = 20;
/**
* 預設箭頭偏移量
*/
public static float DEFAULT_ARROW_OFFSET = 50;
/**
* 氣泡預設背景顏色
*/
public static int DEFAULT_BUBBLE_COLOR = Color.RED;
private RectF mRectF;
private float mArrowWidth = DEFAULT_ARROW_WIDTH;
private float mArrowHeight = DEFAULT_ARROW_HEIGHT;
private float mRadius = DEFAULT_RADIUS;
private float mArrowOffset = DEFAULT_ARROW_OFFSET;
private int mBubbleColor = DEFAULT_BUBBLE_COLOR;
private ArrowDirection mArrowDirection = ArrowDirection.LEFT;
private boolean mArrowCenter;
public Builder rect(RectF rect) {
this.mRectF = rect;
return this;
}
public Builder arrowWidth(float width) {
this.mArrowWidth = width;
return this;
}
public Builder arrowHeight(float height) {
this.mArrowHeight = height;
return this;
}
public Builder radius(float angle) {
this.mRadius = angle; //TODO
return this;
}
public Builder arrowOffset(float position) {
this.mArrowOffset = position;
return this;
}
public Builder bubbleColor(int color) {
this.mBubbleColor = color;
return this;
}
public Builder arrowDirection(ArrowDirection direction) {
this.mArrowDirection = direction;
return this;
}
public Builder arrowCenter(boolean arrowCenter) {
this.mArrowCenter = arrowCenter;
return this;
}
public JooyerBubbleDrawable build() {
if (null == mRectF) {
throw new IllegalArgumentException("BubbleDrawable RectF can not be null");
}
return new JooyerBubbleDrawable(this);
}
}
/**
* 箭頭位置
*/
public enum ArrowDirection {
LEFT(0x00),
TOP(0x01),
RIGHT(0x02),
BOTTOM(0x03);
private int mValue;
ArrowDirection(int value) {
mValue = value;
}
private int getIntValue() {
return mValue;
}
public static ArrowDirection getDefault() {
return LEFT;
}
public static ArrowDirection mapIntToValue(int stateInt) {
for (ArrowDirection value : ArrowDirection.values()) {
if (stateInt == value.getIntValue()) {
return value;
}
}
return getDefault();
}
}
}複製程式碼
自定義屬性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="JooyerBubbleRecyclerView">
<!-- 三角箭頭寬度 -->
<attr name="jooyer_bubble_arrow_width" format="dimension"/>
<!-- 三角箭頭高度 -->
<attr name="jooyer_bubble_arrow_height" format="dimension"/>
<!-- 三角箭頭位置(相對偏移量) -->
<attr name="jooyer_bubble_arrow_offset" format="dimension"/>
<!-- 氣泡圓角半徑 -->
<attr name="jooyer_bubble_arrow_radius" format="dimension"/>
<!-- 氣泡背景顏色 -->
<attr name="jooyer_bubble_arrow_color" format="color"/>
<!-- 三角箭頭是否居中 -->
<attr name="jooyer_bubble_arrow_center" format="boolean"/>
<!-- 三角箭頭方向朝向 -->
<attr name="jooyer_bubble_arrow_direction" format="enum">
<enum name="jooyer_bubble_arrow_direction_left" value="0x00"/>
<enum name="jooyer_bubble_arrow_direction_top" value="0x01"/>
<enum name="jooyer_bubble_arrow_direction_right" value="0x02"/>
<enum name="jooyer_bubble_arrow_direction_bottom" value="0x03"/>
</attr>
</declare-styleable>
</resources>複製程式碼
我們看下它的具體用法:
<?xml version="1.0" encoding="utf-8"?>
<com.jooyerbubblemenu.JooyerBubbleRecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:toools="http://schemas.android.com/tools"
android:id="@+id/rv_top_right_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:jooyer_bubble_arrow_width="8dp"
app:jooyer_bubble_arrow_height="10dp"
app:jooyer_bubble_arrow_offset="20dp"
app:jooyer_bubble_arrow_radius="10dp"
app:jooyer_bubble_arrow_center="false"
app:jooyer_bubble_arrow_color="#fff"
app:jooyer_bubble_arrow_direction="jooyer_bubble_arrow_direction_top"
toools:itemlist="@layout/top_right_menu_item"
/>複製程式碼
接下來,我們看看大神封裝的Item和PopupWindow
package com.jooyerbubblemenu;
/**
* 每一項選單
* Created by Jooyer on 2017/2/10
*/
public class MenuItem {
private int icon;
private String content;
public MenuItem() {
}
public MenuItem(int icon, String content) {
this.icon = icon;
this.content = content;
}
public int getIcon() {
return icon;
}
public void setIcon(int icon) {
this.icon = icon;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}複製程式碼
大神的神劍: TopRightMenu
package com.jooyerbubblemenu;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;
import com.jooyerbubblemenu.utils.LogUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 封裝一個PopupWindow 實現類似QQ,支付寶等右上角彈框效果
* Created by Jooyer on 2017/2/10
*/
public class TopRightMenu {
private static final String TAG = "TopRightMenu";
private static final int DEFAULT_AMEND = 200;
private Context mContext;
private PopupWindow mPopupWindow;
private RecyclerView mRecyclerView;
private View mParent;
private TopRightMenuAdapter mTopRightMenuAdapter;
private List<MenuItem> mItemList;
/**
* 彈窗預設高度
*/
private static final int DEFAULT_HEIGHT = 480;
/**
* 彈窗預設高度
*/
private static final int DEFAULT_WIDTH = 320;
private int mPopupHeight = DEFAULT_HEIGHT;
private int mPopupWidth = DEFAULT_WIDTH;
/**
* 預設顯示圖示
*/
private boolean isShowIcon = true;
/**
* 預設顯示背景 --> 背景變暗
*/
private boolean isShowBackground = true;
/**
* 預設顯示動畫
*/
private boolean isShowAnimationStyle = true;
/**
* 預設彈出或者關閉動畫
*/
private static final int DEFAULT_ANIM_STYLE = R.style.TopRightMenu_Anim;
private int mAnimationStyle;
/**
* 預設的透明度值
*/
private float mAlpha = 0.7f;
public TopRightMenu(Context context) {
mContext = context;
init();
}
private void init() {
mParent = LayoutInflater.from(mContext).inflate(R.layout.top_right_menu, null);
mRecyclerView = (RecyclerView) mParent.findViewById(R.id.rv_top_right_menu);
mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));
mRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
mItemList = new ArrayList<>();
mTopRightMenuAdapter = new TopRightMenuAdapter(mContext, mItemList, isShowIcon, this);
}
/**
* 設定高度
*/
public TopRightMenu setHeight(int height) {
if (height > 0) {
this.mPopupHeight = height;
}
return this;
}
/**
* 設定寬度
*/
public TopRightMenu setWidth(int width) {
if (width > 0) {
this.mPopupWidth = width;
} else {
throw new IllegalArgumentException("寬度不能為空,且必須大於0!");
}
return this;
}
/**
* 設定是否顯示圖示
*/
public TopRightMenu setShowIcon(boolean isShowIcon) {
this.isShowIcon = isShowIcon;
return this;
}
/**
* 設定背景是否變暗
*/
public TopRightMenu setShowBackground(boolean isShowBackground) {
this.isShowBackground = isShowBackground;
return this;
}
/**
* 設定背景顏色變化動畫
*
* @param from --> 開始值
* @param to --> 結束值
* @param duration --> 持續時間
*/
private void setBackgroundAlpha(float from, float to, int duration) {
final WindowManager.LayoutParams lp = ((Activity) mContext).getWindow().getAttributes();
ValueAnimator animator = ValueAnimator.ofFloat(from, to);
animator.setDuration(duration);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
lp.alpha = (float) animation.getAnimatedValue();
((Activity) mContext).getWindow().setAttributes(lp);
}
});
animator.start();
}
/**
* 設定是否顯示動畫
*/
public TopRightMenu setShowAnimationStyle(boolean isShowAnimationStyle) {
this.isShowAnimationStyle = isShowAnimationStyle;
return this;
}
/**
* 設定動畫
*/
public TopRightMenu setAnimationStyle(int animationStyle) {
this.mAnimationStyle = animationStyle;
return this;
}
/**
* 新增單個選單
*/
public TopRightMenu addMenuItem(MenuItem menuItem) {
mItemList.add(menuItem);
return this;
}
/**
* 新增多個選單
*/
public TopRightMenu addMenuItems(List<MenuItem> list) {
mItemList.addAll(list);
return this;
}
public TopRightMenu setOnTopRightMenuItemClickListener(OnTopRightMenuItemClickListener listener) {
mTopRightMenuAdapter.setOnTopRightMenuItemClickListener(listener);
return this;
}
public TopRightMenu showAsDropDown(View anchor) {
showAsDropDown(anchor, 0, 0);
return this;
}
public TopRightMenu setArrowPosition(float value) {
if (mRecyclerView != null && mRecyclerView instanceof JooyerBubbleRecyclerView) {
((JooyerBubbleRecyclerView) mRecyclerView).setArrowOffset(value);
}
return this;
}
public TopRightMenu showAsDropDown(View anchor, int offsetX, int offsetY) {
if (null == mPopupWindow) {
mPopupWindow = getPopupWindow();
}
if (!mPopupWindow.isShowing()) {
mPopupWindow.showAsDropDown(anchor, offsetX, offsetY);
if (isShowBackground)
setBackgroundAlpha(1f, mAlpha, 300);
}
return this;
}
public TopRightMenu show(View anchor, Rect frame, Point origin) {
if (null == mPopupWindow) {
mPopupWindow = getPopupWindow();
}
if (null == frame) frame = new Rect();
if (null == origin) origin = new Point(-1, -1);
int[] location = reviseFrameAndOrigin(anchor, frame, origin);
int x = location[0];
int y = location[1];
LogUtils.i(TAG, "==location====X : " + x + "======Y : " + y);
int width = anchor.getWidth();
int height = anchor.getHeight();
int contentHeight = mPopupWindow.getContentView().getMeasuredHeight();
if (!mPopupWindow.isShowing()) {
if (y + height + contentHeight < frame.bottom) {
mPopupWindow.showAsDropDown(anchor, (int) (-DEFAULT_AMEND - (mPopupWidth - DEFAULT_WIDTH)), 0);
LogUtils.i(TAG, "=====showAsDropDown=====" + (int) (-DEFAULT_AMEND - (mPopupWidth - DEFAULT_WIDTH)));
}
if (isShowBackground)
setBackgroundAlpha(1f, mAlpha, 300);
}
return this;
}
/**
* 確定 彈框的位置
*/
private int[] reviseFrameAndOrigin(View anchor, Rect frame, Point origin) {
int[] location = new int[2];
anchor.getLocationInWindow(location);
if (origin.x < 0 || origin.y < 0) {
origin.set(anchor.getWidth() >> 1, anchor.getHeight() >> 1);
LogUtils.i(TAG, "====1====" + (anchor.getWidth() >> 1) + "=====" + (anchor.getHeight() >> 1)
+ "=======getWidth : " + anchor.getWidth() + "===== : " + anchor.getHeight());
}
if (frame.isEmpty() || !frame.contains(origin.x + location[0], origin.y + location[1])) {
anchor.getWindowVisibleDisplayFrame(frame);
}
LogUtils.i(TAG, "====2====" + (origin.x + location[0]) + "=====" + (origin.y + location[1]));
return location;
}
private PopupWindow getPopupWindow() {
mPopupWindow = new PopupWindow(mContext);
mPopupWindow.setContentView(mParent);
mPopupWindow.setWidth(mPopupWidth);
mPopupWindow.setHeight(mPopupHeight);
if (isShowAnimationStyle)
mPopupWindow.setAnimationStyle(mAnimationStyle <= 0 ? DEFAULT_ANIM_STYLE : mAnimationStyle);
mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
mPopupWindow.setBackgroundDrawable(new ColorDrawable());
mPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
if (isShowBackground)
setBackgroundAlpha(mAlpha, 1f, 300);
}
});
mTopRightMenuAdapter.setItemData(mItemList);
mTopRightMenuAdapter.setShowIcon(isShowIcon);
mRecyclerView.setAdapter(mTopRightMenuAdapter);
return mPopupWindow;
}
public void dismiss() {
if (null != mPopupWindow && mPopupWindow.isShowing())
mPopupWindow.dismiss();
}
}複製程式碼
以上我在不明白的地方列印有日誌輸入,可以瞭解大神用意
最後來看哈使用方式:
package com.jooyerbubblemenu;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ImageView more;
private TopRightMenu mTopRightMenu;
private List<MenuItem> mItems;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initMenu();
more = (ImageView) findViewById(R.id.more);
mTopRightMenu = new TopRightMenu(this);
more.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mTopRightMenu.setWidth(400)
.setHeight(600)
.setShowIcon(true)
.setShowAnimationStyle(true)
.setAnimationStyle(R.style.TopRightMenu_Anim)
.setShowBackground(true)
.setArrowPosition(345f)
.addMenuItems(mItems)
.addMenuItem(new MenuItem(R.mipmap.facetoface,"面對面快傳"))
.addMenuItem(new MenuItem(R.mipmap.pay,"付款"))
.setOnTopRightMenuItemClickListener(new OnTopRightMenuItemClickListener() {
@Override
public void onTopRightMenuItemClick(int position) {
Toast.makeText(MainActivity.this, " 點選位置 :" + position, Toast.LENGTH_SHORT).show();
}
});
mTopRightMenu.show(v,null,null);
}
});
}
private void initMenu() {
mItems = new ArrayList<>();
mItems.add(new MenuItem(R.mipmap.multichat, "發起多人聊天"));
mItems.add(new MenuItem(R.mipmap.addmember, "加好友"));
mItems.add(new MenuItem(R.mipmap.qr_scan, "掃一掃"));
}
}複製程式碼
其執行結果,如開頭所示,這裡主要是對上次 Path 的學習的鞏固!下一次,我將繼續站在大神肩膀上大家分享
附上本次 github 地址: github.com/Jooyer/Jooy…