添加日志窗口标签查找功能
This commit is contained in:
parent
e2b6fadd43
commit
08f990de65
@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Wed Mar 26 16:59:16 GMT 2025
|
#Thu Mar 27 02:41:16 GMT 2025
|
||||||
stageCount=1
|
stageCount=1
|
||||||
libraryProject=libappbase
|
libraryProject=libappbase
|
||||||
baseVersion=15.1
|
baseVersion=15.1
|
||||||
publishVersion=15.1.0
|
publishVersion=15.1.0
|
||||||
buildCount=42
|
buildCount=91
|
||||||
baseBetaVersion=15.1.1
|
baseBetaVersion=15.1.1
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Wed Mar 26 16:59:16 GMT 2025
|
#Thu Mar 27 02:41:16 GMT 2025
|
||||||
stageCount=1
|
stageCount=1
|
||||||
libraryProject=libappbase
|
libraryProject=libappbase
|
||||||
baseVersion=15.1
|
baseVersion=15.1
|
||||||
publishVersion=15.1.0
|
publishVersion=15.1.0
|
||||||
buildCount=42
|
buildCount=91
|
||||||
baseBetaVersion=15.1.1
|
baseBetaVersion=15.1.1
|
||||||
|
@ -10,6 +10,7 @@ import android.content.ClipboardManager;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.text.TextWatcher;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -18,6 +19,7 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.BaseAdapter;
|
import android.widget.BaseAdapter;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
@ -31,6 +33,9 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.widget.HorizontalScrollView;
|
||||||
|
|
||||||
public class LogView extends RelativeLayout {
|
public class LogView extends RelativeLayout {
|
||||||
|
|
||||||
@ -42,6 +47,7 @@ public class LogView extends RelativeLayout {
|
|||||||
Context mContext;
|
Context mContext;
|
||||||
ScrollView mScrollView;
|
ScrollView mScrollView;
|
||||||
TextView mTextView;
|
TextView mTextView;
|
||||||
|
EditText metTagSearch;
|
||||||
CheckBox mSelectableCheckBox;
|
CheckBox mSelectableCheckBox;
|
||||||
CheckBox mSelectAllTAGCheckBox;
|
CheckBox mSelectAllTAGCheckBox;
|
||||||
TAGListAdapter mTAGListAdapter;
|
TAGListAdapter mTAGListAdapter;
|
||||||
@ -107,9 +113,41 @@ public class LogView extends RelativeLayout {
|
|||||||
//
|
//
|
||||||
mScrollView = findViewById(cc.winboll.studio.libappbase.R.id.viewlogScrollViewLog);
|
mScrollView = findViewById(cc.winboll.studio.libappbase.R.id.viewlogScrollViewLog);
|
||||||
mTextView = findViewById(cc.winboll.studio.libappbase.R.id.viewlogTextViewLog);
|
mTextView = findViewById(cc.winboll.studio.libappbase.R.id.viewlogTextViewLog);
|
||||||
|
metTagSearch = findViewById(cc.winboll.studio.libappbase.R.id.tagsearch_et);
|
||||||
// 获取Log Level spinner实例
|
// 获取Log Level spinner实例
|
||||||
mLogLevelSpinner = findViewById(cc.winboll.studio.libappbase.R.id.viewlogSpinner1);
|
mLogLevelSpinner = findViewById(cc.winboll.studio.libappbase.R.id.viewlogSpinner1);
|
||||||
|
|
||||||
|
metTagSearch.addTextChangedListener(new TextWatcher() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable editable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence charSequence, int p, int p1, int p2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
LogUtils.d(TAG, s.toString());
|
||||||
|
if (s.length() > 0) {
|
||||||
|
scrollToTag(s.toString());
|
||||||
|
} else {
|
||||||
|
HorizontalScrollView hsRoot = findViewById(R.id.viewlogHorizontalScrollView1);
|
||||||
|
hsRoot.smoothScrollTo(0, 0);
|
||||||
|
mListViewTags.resetScrollToStart();
|
||||||
|
}
|
||||||
|
// mListViewTags.postDelayed(new Runnable() {
|
||||||
|
// @Override
|
||||||
|
// public void run() {
|
||||||
|
// mListViewTags.scrollToItem(5);
|
||||||
|
// }
|
||||||
|
// }, 100);
|
||||||
|
}
|
||||||
|
// 其他方法留空或按需实现
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
(findViewById(cc.winboll.studio.libappbase.R.id.viewlogButtonClean)).setOnClickListener(new View.OnClickListener(){
|
(findViewById(cc.winboll.studio.libappbase.R.id.viewlogButtonClean)).setOnClickListener(new View.OnClickListener(){
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -233,6 +271,60 @@ public class LogView extends RelativeLayout {
|
|||||||
scrollLogUp();
|
scrollLogUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void scrollToTag(final String prefix) {
|
||||||
|
if (mTAGListAdapter == null || prefix == null || prefix.length() == 0) {
|
||||||
|
LogUtils.d(TAG, "参数为空,无法滚动");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<TAGItemModel> itemList = mTAGListAdapter.getItemList();
|
||||||
|
|
||||||
|
mListViewTags.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// 查找匹配的标签位置
|
||||||
|
int targetPosition = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < itemList.size(); i++) {
|
||||||
|
String tag = itemList.get(i).getTag();
|
||||||
|
if (tag != null && tag.toLowerCase().startsWith(prefix.toLowerCase())) {
|
||||||
|
targetPosition = i;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPosition != -1) {
|
||||||
|
// 优化滚动逻辑
|
||||||
|
//mListViewTags.setSelection(targetPosition);
|
||||||
|
//mListViewTags.invalidateViews(); // 强制刷新所有可见项
|
||||||
|
|
||||||
|
// 单独刷新目标视图
|
||||||
|
// View targetView = mListViewTags.getChildAt(targetPosition);
|
||||||
|
// if (targetView != null) {
|
||||||
|
// targetView.requestLayout();
|
||||||
|
// targetView.requestFocus();
|
||||||
|
// }
|
||||||
|
|
||||||
|
final int scrollPosition = targetPosition;
|
||||||
|
|
||||||
|
// 延迟滚动确保布局完成
|
||||||
|
mListViewTags.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
LogUtils.d(TAG, String.format("scrollPosition %d", scrollPosition));
|
||||||
|
mListViewTags.scrollToItem(scrollPosition);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
LogUtils.d(TAG, "未找到匹配的标签前缀:" + prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class LogViewHandler extends Handler {
|
class LogViewHandler extends Handler {
|
||||||
|
|
||||||
final static int MSG_LOGVIEW_UPDATE = 0;
|
final static int MSG_LOGVIEW_UPDATE = 0;
|
||||||
@ -300,6 +392,30 @@ public class LogView extends RelativeLayout {
|
|||||||
public void setChecked(boolean checked) {
|
public void setChecked(boolean checked) {
|
||||||
isChecked = checked;
|
isChecked = checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getter/setter...
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TAGItemModel that = (TAGItemModel) o;
|
||||||
|
// 手动处理空值比较(Java 6 不支持 Objects.equals)
|
||||||
|
if (tag == null) {
|
||||||
|
return that.tag == null;
|
||||||
|
} else {
|
||||||
|
return tag.equals(that.tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return tag == null ? 0 : tag.hashCode(); // 手动处理空值
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -315,6 +431,10 @@ public class LogView extends RelativeLayout {
|
|||||||
loadMap(mapOrigin);
|
loadMap(mapOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TAGItemModel> getItemList() {
|
||||||
|
return itemList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return itemList.size();
|
return itemList.size();
|
||||||
@ -344,7 +464,7 @@ public class LogView extends RelativeLayout {
|
|||||||
loadMap(mapOrigin);
|
loadMap(mapOrigin);
|
||||||
super.notifyDataSetChanged();
|
super.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
ViewHolder holder;
|
ViewHolder holder;
|
||||||
|
@ -9,23 +9,34 @@ import android.content.Context;
|
|||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
import android.widget.Scroller;
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
|
|
||||||
public class HorizontalListView extends ListView {
|
public class HorizontalListView extends ListView {
|
||||||
|
|
||||||
public static final String TAG = "HorizontalListView";
|
public static final String TAG = "HorizontalListView";
|
||||||
int verticalOffset = 0;
|
private int verticalOffset = 0;
|
||||||
|
private Scroller scroller;
|
||||||
|
private int totalWidth;
|
||||||
|
|
||||||
public HorizontalListView(Context context) {
|
public HorizontalListView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HorizontalListView(Context context, AttributeSet attrs) {
|
public HorizontalListView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public HorizontalListView(Context context, AttributeSet attrs, int defStyle) {
|
public HorizontalListView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
super(context, attrs, defStyle);
|
super(context, attrs, defStyle);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
scroller = new Scroller(getContext());
|
||||||
|
setHorizontalScrollBarEnabled(true);
|
||||||
|
setVerticalScrollBarEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerticalOffset(int verticalOffset) {
|
public void setVerticalOffset(int verticalOffset) {
|
||||||
@ -38,28 +49,81 @@ public class HorizontalListView extends ListView {
|
|||||||
int childCount = getChildCount();
|
int childCount = getChildCount();
|
||||||
int left = getPaddingLeft();
|
int left = getPaddingLeft();
|
||||||
int viewHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
|
int viewHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
|
||||||
LogUtils.d(TAG, String.format("HorizontalListView的高度 %d", viewHeight));
|
totalWidth = left;
|
||||||
|
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
View child = getChildAt(i);
|
View child = getChildAt(i);
|
||||||
// 计算每个子视图的宽度和高度
|
|
||||||
int width = child.getMeasuredWidth();
|
int width = child.getMeasuredWidth();
|
||||||
int height = child.getMeasuredHeight();
|
int height = child.getMeasuredHeight();
|
||||||
//LogUtils.d(TAG, String.format("child : width %d , height %d", width, height));
|
|
||||||
// 设置子视图的位置,实现水平布局
|
|
||||||
|
|
||||||
child.layout(left, verticalOffset, left + width, verticalOffset + height);
|
child.layout(left, verticalOffset, left + width, verticalOffset + height);
|
||||||
left += width;
|
left += width;
|
||||||
}
|
}
|
||||||
|
totalWidth = left + getPaddingRight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
|
int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
|
||||||
//super.onMeasure(widthMeasureSpec, newHeightMeasureSpec);
|
|
||||||
int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
|
int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
|
||||||
//LogUtils.d(TAG, String.format("newWidthMeasureSpec %d, newHeightMeasureSpec %d", newWidthMeasureSpec, newHeightMeasureSpec));
|
|
||||||
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
|
super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void computeScroll() {
|
||||||
|
if (scroller.computeScrollOffset()) {
|
||||||
|
scrollTo(scroller.getCurrX(), scroller.getCurrY());
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void smoothScrollTo(int x, int y) {
|
||||||
|
int dx = x - getScrollX();
|
||||||
|
int dy = y - getScrollY();
|
||||||
|
scroller.startScroll(getScrollX(), getScrollY(), dx, dy, 300); // 300ms平滑动画
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int computeHorizontalScrollRange() {
|
||||||
|
return totalWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int computeHorizontalScrollOffset() {
|
||||||
|
return getScrollX();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int computeHorizontalScrollExtent() {
|
||||||
|
return getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scrollToItem(int position) {
|
||||||
|
if (position < 0 || position >= getChildCount()) {
|
||||||
|
LogUtils.d(TAG, "无效的position: " + position);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
View targetView = getChildAt(position);
|
||||||
|
int targetLeft = targetView.getLeft();
|
||||||
|
int scrollX = targetLeft - getPaddingLeft();
|
||||||
|
|
||||||
|
// 修正最大滚动范围计算
|
||||||
|
int maxScrollX = totalWidth;
|
||||||
|
scrollX = Math.max(0, Math.min(scrollX, maxScrollX));
|
||||||
|
|
||||||
|
// 强制重新布局和绘制
|
||||||
|
requestLayout();
|
||||||
|
invalidateViews();
|
||||||
|
smoothScrollTo(scrollX, 0);
|
||||||
|
LogUtils.d(TAG, String.format("滚动到position: %d, scrollX: %d computeHorizontalScrollRange() %d", position, scrollX, computeHorizontalScrollRange()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetScrollToStart() {
|
||||||
|
// 强制重新布局和绘制
|
||||||
|
requestLayout();
|
||||||
|
invalidateViews();
|
||||||
|
smoothScrollTo(0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +83,21 @@
|
|||||||
android:layout_marginLeft="5dp"
|
android:layout_marginLeft="5dp"
|
||||||
android:layout_marginRight="5dp"/>
|
android:layout_marginRight="5dp"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:ems="10"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:id="@+id/tagsearch_et"/>
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@drawable/bg_border"
|
android:background="@drawable/bg_border"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:layout_weight="1.0">
|
android:layout_weight="1.0"
|
||||||
|
android:id="@+id/viewlogHorizontalScrollView1">
|
||||||
|
|
||||||
<cc.winboll.studio.libappbase.views.HorizontalListView
|
<cc.winboll.studio.libappbase.views.HorizontalListView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user