Skip to content

Commit b2a2bbb

Browse files
guangyaoguangyao
authored andcommitted
2 parents 92359eb + a6d8d11 commit b2a2bbb

File tree

6 files changed

+270
-10
lines changed

6 files changed

+270
-10
lines changed
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
package cn.jiguang.imui.messages;
2+
3+
import android.text.Layout;
4+
import android.text.NoCopySpan;
5+
import android.text.Selection;
6+
import android.text.Spannable;
7+
import android.text.method.MovementMethod;
8+
import android.text.method.ScrollingMovementMethod;
9+
import android.text.style.ClickableSpan;
10+
import android.view.KeyEvent;
11+
import android.view.MotionEvent;
12+
import android.view.View;
13+
import android.widget.TextView;
14+
15+
/**
16+
* Created by dowin on 2017/10/9.
17+
*/
18+
19+
public class ClickLinkMovementMethod extends ScrollingMovementMethod {
20+
private static final int CLICK = 1;
21+
private static final int UP = 2;
22+
private static final int DOWN = 3;
23+
24+
@Override
25+
public boolean canSelectArbitrarily() {
26+
return true;
27+
}
28+
29+
@Override
30+
protected boolean handleMovementKey(TextView widget, Spannable buffer, int keyCode,
31+
int movementMetaState, KeyEvent event) {
32+
switch (keyCode) {
33+
case KeyEvent.KEYCODE_DPAD_CENTER:
34+
case KeyEvent.KEYCODE_ENTER:
35+
if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {
36+
if (event.getAction() == KeyEvent.ACTION_DOWN &&
37+
event.getRepeatCount() == 0 && action(CLICK, widget, buffer)) {
38+
return true;
39+
}
40+
}
41+
break;
42+
}
43+
return super.handleMovementKey(widget, buffer, keyCode, movementMetaState, event);
44+
}
45+
46+
@Override
47+
protected boolean up(TextView widget, Spannable buffer) {
48+
if (action(UP, widget, buffer)) {
49+
return true;
50+
}
51+
52+
return super.up(widget, buffer);
53+
}
54+
55+
@Override
56+
protected boolean down(TextView widget, Spannable buffer) {
57+
if (action(DOWN, widget, buffer)) {
58+
return true;
59+
}
60+
61+
return super.down(widget, buffer);
62+
}
63+
64+
@Override
65+
protected boolean left(TextView widget, Spannable buffer) {
66+
if (action(UP, widget, buffer)) {
67+
return true;
68+
}
69+
70+
return super.left(widget, buffer);
71+
}
72+
73+
@Override
74+
protected boolean right(TextView widget, Spannable buffer) {
75+
if (action(DOWN, widget, buffer)) {
76+
return true;
77+
}
78+
79+
return super.right(widget, buffer);
80+
}
81+
82+
private boolean action(int what, TextView widget, Spannable buffer) {
83+
Layout layout = widget.getLayout();
84+
85+
int padding = widget.getTotalPaddingTop() +
86+
widget.getTotalPaddingBottom();
87+
int areatop = widget.getScrollY();
88+
int areabot = areatop + widget.getHeight() - padding;
89+
90+
int linetop = layout.getLineForVertical(areatop);
91+
int linebot = layout.getLineForVertical(areabot);
92+
93+
int first = layout.getLineStart(linetop);
94+
int last = layout.getLineEnd(linebot);
95+
96+
ClickableSpan[] candidates = buffer.getSpans(first, last, ClickableSpan.class);
97+
98+
int a = Selection.getSelectionStart(buffer);
99+
int b = Selection.getSelectionEnd(buffer);
100+
101+
int selStart = Math.min(a, b);
102+
int selEnd = Math.max(a, b);
103+
104+
if (selStart < 0) {
105+
if (buffer.getSpanStart(FROM_BELOW) >= 0) {
106+
selStart = selEnd = buffer.length();
107+
}
108+
}
109+
110+
if (selStart > last)
111+
selStart = selEnd = Integer.MAX_VALUE;
112+
if (selEnd < first)
113+
selStart = selEnd = -1;
114+
115+
switch (what) {
116+
case CLICK:
117+
if (selStart == selEnd) {
118+
return false;
119+
}
120+
121+
ClickableSpan[] link = buffer.getSpans(selStart, selEnd, ClickableSpan.class);
122+
123+
if (link.length != 1)
124+
return false;
125+
126+
link[0].onClick(widget);
127+
break;
128+
129+
case UP:
130+
int beststart, bestend;
131+
132+
beststart = -1;
133+
bestend = -1;
134+
135+
for (int i = 0; i < candidates.length; i++) {
136+
int end = buffer.getSpanEnd(candidates[i]);
137+
138+
if (end < selEnd || selStart == selEnd) {
139+
if (end > bestend) {
140+
beststart = buffer.getSpanStart(candidates[i]);
141+
bestend = end;
142+
}
143+
}
144+
}
145+
146+
if (beststart >= 0) {
147+
Selection.setSelection(buffer, bestend, beststart);
148+
return true;
149+
}
150+
151+
break;
152+
153+
case DOWN:
154+
beststart = Integer.MAX_VALUE;
155+
bestend = Integer.MAX_VALUE;
156+
157+
for (int i = 0; i < candidates.length; i++) {
158+
int start = buffer.getSpanStart(candidates[i]);
159+
160+
if (start > selStart || selStart == selEnd) {
161+
if (start < beststart) {
162+
beststart = start;
163+
bestend = buffer.getSpanEnd(candidates[i]);
164+
}
165+
}
166+
}
167+
168+
if (bestend < Integer.MAX_VALUE) {
169+
Selection.setSelection(buffer, beststart, bestend);
170+
return true;
171+
}
172+
173+
break;
174+
}
175+
176+
return false;
177+
}
178+
179+
@Override
180+
public boolean onTouchEvent(TextView widget, Spannable buffer,
181+
MotionEvent event) {
182+
int action = event.getAction();
183+
184+
if (action == MotionEvent.ACTION_UP ||
185+
action == MotionEvent.ACTION_DOWN) {
186+
int x = (int) event.getX();
187+
int y = (int) event.getY();
188+
189+
x -= widget.getTotalPaddingLeft();
190+
y -= widget.getTotalPaddingTop();
191+
192+
x += widget.getScrollX();
193+
y += widget.getScrollY();
194+
195+
Layout layout = widget.getLayout();
196+
int line = layout.getLineForVertical(y);
197+
int off = layout.getOffsetForHorizontal(line, x);
198+
199+
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
200+
201+
if (link.length != 0) {
202+
if (action == MotionEvent.ACTION_UP) {
203+
// Log.w("MoonUtil", System.currentTimeMillis() + "-" + lastClickTime);
204+
if (System.currentTimeMillis() - lastClickTime < CLICK_DELAY) {
205+
link[0].onClick(widget);
206+
}
207+
} else if (action == MotionEvent.ACTION_DOWN) {
208+
Selection.setSelection(buffer,
209+
buffer.getSpanStart(link[0]),
210+
buffer.getSpanEnd(link[0]));
211+
lastClickTime = System.currentTimeMillis();
212+
}
213+
214+
return true;
215+
} else {
216+
Selection.removeSelection(buffer);
217+
}
218+
}
219+
220+
return super.onTouchEvent(widget, buffer, event);
221+
}
222+
223+
@Override
224+
public void initialize(TextView widget, Spannable text) {
225+
Selection.removeSelection(text);
226+
text.removeSpan(FROM_BELOW);
227+
}
228+
229+
@Override
230+
public void onTakeFocus(TextView view, Spannable text, int dir) {
231+
Selection.removeSelection(text);
232+
233+
if ((dir & View.FOCUS_BACKWARD) != 0) {
234+
text.setSpan(FROM_BELOW, 0, 0, Spannable.SPAN_POINT_POINT);
235+
} else {
236+
text.removeSpan(FROM_BELOW);
237+
}
238+
}
239+
240+
public static MovementMethod getInstance() {
241+
if (sInstance == null)
242+
sInstance = new ClickLinkMovementMethod();
243+
244+
return sInstance;
245+
}
246+
247+
private static MovementMethod sInstance;
248+
private static Object FROM_BELOW = new NoCopySpan.Concrete();
249+
private static final long CLICK_DELAY = 500l;
250+
private long lastClickTime;
251+
}

android/messagelist/src/main/java/cn/jiguang/imui/messages/MsgListAdapter.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,18 @@ private class Wrapper<DATA> {
374374
* @param messages message to be add
375375
* @param scrollToBottom if true scroll list to bottom
376376
*/
377-
public void addToStart(List<MESSAGE> messages, boolean scrollToBottom) {
377+
public void addToStart(List<MESSAGE> messages, boolean scrollToBottom, boolean check) {
378378
boolean first = mItems.isEmpty();
379379
updateShowTimeItem(messages, first, true);
380380
for (int i = 0; i < messages.size(); i++) {//3 2 1
381381
MESSAGE message = messages.get(i);
382382

383+
if (check) {
384+
int position = getMessagePositionById(message.getMsgId());
385+
if (position >= 0) {
386+
continue;
387+
}
388+
}
383389
mItems.add(0, new Wrapper<>(message));
384390
notifyItemRangeInserted(0, 1);
385391
addImage(message, false);
@@ -520,10 +526,10 @@ public void updateMessage(String oldId, MESSAGE newMessage) {
520526
if (mLayoutManager != null) {
521527
mLayoutManager.requestLayout();
522528
}
523-
}else {
529+
} else {
524530
List<MESSAGE> list = new ArrayList<>();
525531
list.add(newMessage);
526-
addToStart(list,true);
532+
addToStart(list, true, false);
527533
}
528534

529535
}

android/messagelist/src/main/java/cn/jiguang/imui/messages/viewholder/TxtViewHolder.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.graphics.Color;
44
import android.support.v7.widget.RecyclerView;
5-
import android.text.method.LinkMovementMethod;
65
import android.text.style.ImageSpan;
76
import android.util.Log;
87
import android.view.Gravity;
@@ -12,6 +11,7 @@
1211
import cn.jiguang.imui.BuildConfig;
1312
import cn.jiguang.imui.R;
1413
import cn.jiguang.imui.commons.models.IMessage;
14+
import cn.jiguang.imui.messages.ClickLinkMovementMethod;
1515
import cn.jiguang.imui.messages.MessageListStyle;
1616
import dowin.com.emoji.emoji.LinkClick;
1717
import dowin.com.emoji.emoji.MoonUtil;
@@ -47,7 +47,7 @@ public void onClick(View widget, String url) {
4747
} else {
4848
mMsgTv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
4949
}
50-
mMsgTv.setMovementMethod(LinkMovementMethod.getInstance());
50+
mMsgTv.setMovementMethod(ClickLinkMovementMethod.getInstance());
5151

5252
// mMsgTv.setOnClickListener(new View.OnClickListener() {
5353
// @Override
@@ -61,6 +61,7 @@ public void onClick(View widget, String url) {
6161
mMsgTv.setOnLongClickListener(new View.OnLongClickListener() {
6262
@Override
6363
public boolean onLongClick(View view) {
64+
// Log.w("MoonUtil", mMsgTv.getMovementMethod().getClass().getName());
6465
if (mMsgLongClickListener != null) {
6566
mMsgLongClickListener.onMessageLongClick(message);
6667
} else {
@@ -78,6 +79,8 @@ public void applyStyle(MessageListStyle style) {
7879
super.applyStyle(style);
7980
mMsgTv.setMaxWidth((int) (style.getWindowWidth() * style.getBubbleMaxWidth()));
8081
mMsgTv.setTextSize(18);
82+
mMsgTv.setTextIsSelectable(false);
83+
mMsgTv.setClickable(false);
8184
mMsgTv.setTextColor(mIsSender ? Color.WHITE : Color.BLACK);
8285
mMsgTv.setLinkTextColor(mIsSender ? Color.parseColor("#bbdcff") : Color.parseColor("#238dfa"));
8386

android/messagelist/src/main/res/layout/item_receive_txt.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
style="@style/aurora_msgitem_msg_txt_style"
3030
android:autoLink="all"
3131
android:textColor="@color/black"
32-
android:textIsSelectable="true"
32+
android:textIsSelectable="false"
3333
android:layout_width="wrap_content"
3434
android:layout_height="wrap_content"
3535
android:layout_below="@id/aurora_tv_msgitem_display_name"

android/messagelist/src/main/res/layout/item_send_text.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
style="@style/aurora_msgitem_msg_txt_style"
4040
android:autoLink="all"
4141
android:textColor="@color/white"
42-
android:textIsSelectable="true"
42+
android:textIsSelectable="false"
4343
android:layout_width="wrap_content"
4444
android:layout_height="wrap_content"
4545
android:background="@drawable/aurora_sendtxt_bubble"

android/src/main/java/cn/jiguang/imui/messagelist/ReactMsgListManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public void loadAvatarImage(ImageView avatarImageView, String string) {
127127
return;
128128
}
129129
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
130-
if(reactContext.getCurrentActivity().isDestroyed()){
130+
if (reactContext.getCurrentActivity().isDestroyed()) {
131131
return;
132132
}
133133
}
@@ -392,7 +392,7 @@ public void setInitList(MessageList messageList, ReadableArray messages) {
392392
RCTMessage rctMessage = configMessage(messages.getMap(i));
393393
list.add(rctMessage);
394394
}
395-
mAdapter.addToStart(list, true);
395+
mAdapter.addToStart(list, true, false);
396396
}
397397
}
398398

@@ -508,7 +508,7 @@ public void onReceive(Context context, Intent intent) {
508508
activity.runOnUiThread(new Runnable() {
509509
@Override
510510
public void run() {
511-
mAdapter.addToStart(list, false);
511+
mAdapter.addToStart(list, false, true);
512512
}
513513
});
514514
}

0 commit comments

Comments
 (0)