android qq 长按删除不了,android 仿QQ聊天长按复制,删除,转发

1:顶部空间过小,自动在下面展现弹出框

2:提示的三角始终在Item的正中间

看看效果图:

25dac173ab00?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

123.png

25dac173ab00?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

9$AI{R64V{HSU15{6SCI4DV.png

25dac173ab00?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

3`YX$598W{CG@98FH~35CWP.png

QQTipView

public class QQTipView extends View {

private static final int STATUS_DOWN = 1;

private static final int STATUS_UP = 2;

// 初始窗口的Item显示在上方

private int mStatus = STATUS_UP;

// 分隔Item之间的线

private int mSeparateLineColor;

// 最边上两个方块的边角半径大小

private int mCorner = dip2px(6);

private Paint mPaint; // 画方块和文字的画笔

private Paint doPaint; // 画三角的画笔

private Path mPath; // 绘制的路径

// 提示窗口与屏幕(根布局)的最小距离

private int mBorderMargin = dip2px(5);

// 窗口Item的宽度

private int mItemWidth = dip2px(50);

// 窗口Item的高度

private int mItemHeight = dip2px(38);

// 三角小标的顶点

private int mTriangleTop = dip2px(40);

// 三角小标的半宽

private int mHalfTriangleWidth = dip2px(6);

// 三角小标与窗口Item的临界

private int mItemBorder;

// 窗口的left值

private int realLeft;

// 存储每个Item的信息

private List mItemList = new ArrayList<>();

// 存储每个方块

private List mItemRectList = new ArrayList<>();

// Item点击接口

private OnItemClickListener onItemClickListener;

// 是否有Item被按下,是为Item的序号,否为-1

private int choose = -1;

// 外界出入的x坐标

private int x;

// 外界传入的y坐标

private int y;

public QQTipView(Context context, ViewGroup rootView, int x, int y, List mItemList) {

super(context);

// 设置传入过来的x轴坐标

this.x = x;

// 设置传入过来的y轴坐标

this.y = y - mItemHeight - mBorderMargin; // x和y决定了三角下标的位置

// 初始化画笔

initPaint();

// 初始化Item集合,并对Item的字符串长度进行处理

setTipItemList(mItemList);

// 将TipView实例添加到传入的rootView中。

addView(rootView);

// 根据传入的点击坐标x、y进行状态判断和最左位置的处理

initView();

}

private void initPaint() {

mPath = new Path();

mPaint = new Paint();

mPaint.setAntiAlias(true);

mPaint.setStyle(Paint.Style.FILL);

mPaint.setTextSize(sp2px(14));

doPaint = new Paint();

doPaint.setAntiAlias(true);

doPaint.setStyle(Paint.Style.FILL);

doPaint.setColor(Color.DKGRAY);

}

private void initView() {

// 获取屏幕宽度

int mScreenWidth = getResources().getDisplayMetrics().widthPixels;

// 点击范围比较小,弹出框显示在下面

if (y / 2 < mItemHeight) {

// 令窗口在下方显示

mStatus = STATUS_DOWN;

// 设置三角下标的顶点

mTriangleTop = y + dip2px(6);

// 设置三角下标和窗口方块的交界处

mItemBorder = mTriangleTop + dip2px(7);

} else {

mStatus = STATUS_UP; // 同理如上

mTriangleTop = y - dip2px(6);

mItemBorder = mTriangleTop - dip2px(7);

}

// 获取当Item数量两边对称时,窗口的Item值:

realLeft = x - (mItemWidth * mItemList.size()) / 2;

if (realLeft < 0) {

// 跑出屏幕左边的话,令值为距离值

realLeft = mBorderMargin;

// 防止三角下标与方块分离

if (x - mCorner <= realLeft) x = realLeft + mCorner * 2;

} else if (realLeft + (mItemWidth * mItemList.size()) > mScreenWidth) {

// 跑出屏幕右边的话,则减去溢出的宽度,再减去距离值

realLeft -= realLeft + (mItemWidth * mItemList.size()) - mScreenWidth + mBorderMargin;

// 防止三角下标与方块分离

if (x + mCorner >= realLeft + mItemWidth * mItemList.size())

x = realLeft + mItemWidth * mItemList.size() - mCorner * 2;

}

}

private void addView(ViewGroup rootView) {

rootView.addView(this, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

// 令背景为透明

drawBackground(canvas);

switch (mStatus) {

case STATUS_DOWN:

// 向下绘制窗口

drawItemDown(canvas);

break;

case STATUS_UP:

// 向上绘制窗口

drawItemUp(canvas);

break;

default:

break;

}

}

private void drawItemDown(Canvas canvas) {

// 清理方块集合

mItemRectList.clear();

mPath.reset(); // 清理路径

// 绘制三角下标:根据是否有Item被点击绘制不同颜色

if (choose != -1)

doPaint.setColor(Color.DKGRAY);

else

doPaint.setColor(Color.BLACK);

mPath.moveTo(x, mTriangleTop);

mPath.lineTo(x - mHalfTriangleWidth, mItemBorder);

mPath.lineTo(x + mHalfTriangleWidth, mItemBorder);

canvas.drawPath(mPath, doPaint);

for (int i = 0; i < mItemList.size(); i++) {

// 当有方块Item被点击时,绘制不同颜色

if (choose == i) {

mPaint.setColor(Color.DKGRAY);

} else {

mPaint.setColor(Color.BLACK);

}

// 绘制第一个方块

if (i == 0) {

mPath.reset();

mPath.moveTo(realLeft + mItemWidth, mItemBorder);

mPath.lineTo(realLeft + mCorner, mItemBorder);

mPath.quadTo(realLeft, mItemBorder

, realLeft, mItemBorder + mCorner);

mPath.lineTo(realLeft, mItemBorder + mItemHeight - mCorner);

mPath.quadTo(realLeft, mItemBorder + mItemHeight

, realLeft + mCorner, mItemBorder + mItemHeight);

mPath.lineTo(realLeft + mItemWidth, mItemBorder + mItemHeight);

canvas.drawPath(mPath, mPaint);

// 绘制第一条分隔线

mPaint.setColor(mSeparateLineColor);

canvas.drawLine(realLeft + mItemWidth, mItemBorder

, realLeft + mItemWidth, mItemBorder + mItemHeight, mPaint);

} else if (i == mItemList.size() - 1) {

// 绘制最后一个方块

mPath.reset();

mPath.moveTo(realLeft + mItemWidth * (mItemList.size() - 1), mItemBorder);

mPath.lineTo(realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth - mCorner, mItemBorder);

mPath.quadTo(realLeft + mItemWidth * (mItemList.size() - 1) + +mItemWidth, mItemBorder

, realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth, mItemBorder + mCorner);

mPath.lineTo(realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth, mItemBorder + mItemHeight - mCorner);

mPath.quadTo(realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth, mItemBorder + mItemHeight,

realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth - mCorner, mItemBorder + mItemHeight);

mPath.lineTo(realLeft + mItemWidth * (mItemList.size() - 1), mItemBorder + mItemHeight);

canvas.drawPath(mPath, mPaint);

// 最后一个方块不需要绘制分割线

} else {

// 绘制中间方块

canvas.drawRect(realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth, mItemBorder

, realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder + mItemHeight, mPaint);

// 绘制其他分隔线

mPaint.setColor(mSeparateLineColor);

canvas.drawLine(realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder

, realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder + mItemHeight, mPaint);

}

// 添加方块到方块集合

mItemRectList.add(new Rect(realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth, mItemBorder, realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder + mItemHeight));

}

// 绘制方块上文字

drawTitle(canvas);

}

public void clean() {

mItemRectList.clear();

mPath.reset();

doPaint.reset();

x = 0;

y = 0;

}

// 可参考drawItemDown

private void drawItemUp(Canvas canvas) {

mItemRectList.clear();

mPath.reset();

if (choose != -1)

doPaint.setColor(Color.DKGRAY);

else

doPaint.setColor(Color.BLACK);

mPath.moveTo(x, mTriangleTop);

mPath.lineTo(x - mHalfTriangleWidth, mItemBorder);

mPath.lineTo(x + mHalfTriangleWidth, mItemBorder);

canvas.drawPath(mPath, doPaint);

for (int i = 0; i < mItemList.size(); i++) {

if (choose == i) {

mPaint.setColor(Color.DKGRAY);

} else {

mPaint.setColor(Color.BLACK);

}

if (i == 0) {

mPath.reset();

mPath.moveTo(realLeft + mItemWidth, mItemBorder - mItemHeight);

mPath.lineTo(realLeft + mCorner, mItemBorder - mItemHeight);

mPath.quadTo(realLeft, mItemBorder - mItemHeight

, realLeft, mItemBorder - mItemHeight + mCorner);

mPath.lineTo(realLeft, mItemBorder - mCorner);

mPath.quadTo(realLeft, mItemBorder

, realLeft + mCorner, mItemBorder);

mPath.lineTo(realLeft + mItemWidth, mItemBorder);

canvas.drawPath(mPath, mPaint);

mPaint.setColor(mSeparateLineColor);

canvas.drawLine(realLeft + mItemWidth, mItemBorder - mItemHeight

, realLeft + mItemWidth, mItemBorder, mPaint);

} else if (i == mItemList.size() - 1) {

mPath.reset();

mPath.moveTo(realLeft + mItemWidth * (mItemList.size() - 1), mItemBorder - mItemHeight);

mPath.lineTo(realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth - mCorner, mItemBorder - mItemHeight);

mPath.quadTo(realLeft + mItemWidth * (mItemList.size() - 1) + +mItemWidth, mItemBorder - mItemHeight

, realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth, mItemBorder - mItemHeight + mCorner);

mPath.lineTo(realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth, mItemBorder - mCorner);

mPath.quadTo(realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth, mItemBorder,

realLeft + mItemWidth * (mItemList.size() - 1) + mItemWidth - mCorner, mItemBorder);

mPath.lineTo(realLeft + mItemWidth * (mItemList.size() - 1), mItemBorder);

canvas.drawPath(mPath, mPaint);

} else {

canvas.drawRect(realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth, mItemBorder - mItemHeight

, realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder, mPaint);

mPaint.setColor(mSeparateLineColor);

canvas.drawLine(realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder - mItemHeight

, realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder, mPaint);

}

mItemRectList.add(new Rect(realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth, mItemBorder - mItemHeight, realLeft + mItemWidth * (mItemList.size() - 1) - (mItemList.size() - (i + 1)) * mItemWidth + mItemWidth, mItemBorder));

}

drawTitle(canvas);

}

// 绘制窗口上的文字

private void drawTitle(Canvas canvas) {

QQTipItem tipItem;

for (int i = 0; i < mItemRectList.size(); i++) {

tipItem = mItemList.get(i);

mPaint.setColor(tipItem.getTextColor());

if (mStatus == STATUS_UP) {

canvas.drawText(tipItem.getTitle(), mItemRectList.get(i).left + mItemWidth / 2 - getTextWidth(tipItem.getTitle(), mPaint) / 2, mItemBorder - mItemHeight / 2 + getTextHeight(mPaint) / 2, mPaint);

} else if (mStatus == STATUS_DOWN) {

canvas.drawText(tipItem.getTitle(), mItemRectList.get(i).left + mItemWidth / 2 - getTextWidth(tipItem.getTitle(), mPaint) / 2, mItemRectList.get(i).bottom - mItemHeight / 2 + getTextHeight(mPaint) / 2, mPaint);

}

}

}

private void drawBackground(Canvas canvas) {

canvas.drawColor(Color.TRANSPARENT);

}

public void setTipItemList(final List list) {

mItemList.clear();

List items = list;

for (QQTipItem item : items) {

if (!TextUtils.isEmpty(item.getTitle())) {

item.setTitle(updateTitle(item.getTitle()));

} else {

item.setTitle("");

}

mItemList.add(item);

}

}

private String updateTitle(String title) {

int textLength = title.length();

String suffix = "";

while (getTextWidth(title.substring(0, textLength) + "...", mPaint) > mItemWidth - dip2px(10)) {

textLength--;

suffix = "...";

}

return title.substring(0, textLength) + suffix;

}

public void setSeparateLineColor(int separateLineColor) {

mSeparateLineColor = separateLineColor;

}

private int dip2px(float dipValue) {

final float scale = getContext().getResources().getDisplayMetrics().density;

return (int) (dipValue * scale + 0.5f);

}

private float getTextHeight(Paint paint) {

Paint.FontMetrics fontMetrics = paint.getFontMetrics();

return fontMetrics.bottom - fontMetrics.descent - fontMetrics.ascent;

}

private float getTextWidth(String text, Paint paint) {

return paint.measureText(text);

}

private int sp2px(float spValue) {

final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;

return (int) (spValue * fontScale + 0.5f);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

for (int i = 0; i < mItemRectList.size(); i++) {

if (onItemClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {

// 被按下时,choose值为当前方块Item序号

choose = i;

// 更新视图

postInvalidate(mItemRectList.get(i).left, mItemRectList.get(i).top, mItemRectList.get(i).right, mItemRectList.get(i).bottom);

}

}

return true;

case MotionEvent.ACTION_UP:

for (int i = 0; i < mItemRectList.size(); i++) {

if (onItemClickListener != null && isPointInRect(new PointF(event.getX(), event.getY()), mItemRectList.get(i))) {

// 触发方法,传入两个参数

onItemClickListener.onItemClick(mItemList.get(i).getTitle(), i);

choose = -1;

}

}

if (onItemClickListener != null) {

clean();

onItemClickListener.dismiss(); // 触发方法

}

removeView(); // 移除TipView

return true;

}

return true;

}

private void removeView() {

ViewGroup vg = (ViewGroup) this.getParent();

if (vg != null) {

vg.removeView(this);

}

}

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;

}

private void setOnItemClickListener(OnItemClickListener onItemClickListener) {

this.onItemClickListener = onItemClickListener;

}

public interface OnItemClickListener {

void onItemClick(String name, int position);

void dismiss();

}

public static class Builder {

private OnItemClickListener onItemClickListener;

private Context mContext;

private ViewGroup mRootView;

private List mTipItemList = new ArrayList<>();

private int mSeparateLineColor = Color.WHITE;

private int x, y;

public Builder(Context context, ViewGroup rootView, int x, int y) {

mContext = context;

mRootView = rootView;

this.x = x;

this.y = y;

}

public Builder addItem(QQTipItem tipItem) {

mTipItemList.add(tipItem);

return this;

}

public Builder addItems(List list) {

mTipItemList.addAll(list);

return this;

}

public Builder setSeparateLineColor(int color) {

mSeparateLineColor = color;

return this;

}

public Builder setOnItemClickListener(OnItemClickListener onItemClickListener) {

this.onItemClickListener = onItemClickListener;

return this;

}

public QQTipView create() {

QQTipView flipShare = new QQTipView(mContext, mRootView, x, y, mTipItemList);

flipShare.setOnItemClickListener(onItemClickListener);

flipShare.setSeparateLineColor(mSeparateLineColor);

return flipShare;

}

}

QQTipItem

public class QQTipItem {

private String title;

private int textColor = Color.WHITE;

public QQTipItem(String title) {

this.title = title;

}

public QQTipItem(String title, int textColor) {

this.title = title;

this.textColor = textColor;

}

public String getTitle() {

return title;

}

public int getTextColor() {

return textColor;

}

public void setTextColor(int textColor) {

this.textColor = textColor;

}

public void setTitle(String title) {

this.title = title;

}

}

使用姿势

@Override

public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) {

final Message message = (Message) parent.getAdapter().getItem(position);

if (message == null) {

return false;

}

int[] location = new int[2];

view.getLocationOnScreen(location);

float OldListY = (float) location[1];

float OldListX = (float) location[0];

new QQTipView.Builder(ConversationChatActivity.this, rootConversation, (int) OldListX + view.getWidth() / 2, (int) OldListY)

.addItem(new QQTipItem("复制"))

.addItem(new QQTipItem("删除"))

.addItem(new QQTipItem("收藏"))

.addItem(new QQTipItem("转发"))

.setOnItemClickListener(new QQTipView.OnItemClickListener() {

@Override

public void onItemClick(String str, final int position) {

if (position == 0) {

ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);

// 将文本内容放到系统剪贴板里。

cm.setText(message.getSummary());

} else if (position == 1) {

message.remove();

chatAdapter.remove(message);

} else if (position == 2) {

showToask("撤回");

} else {

showToask("转发");

}

}

@Override

public void dismiss() {

}

})

.create();

return true;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值