短信发送窗口UI优化
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Thu Jul 03 13:50:15 HKT 2025
|
#Sat Aug 23 05:36:15 GMT 2025
|
||||||
stageCount=2
|
stageCount=2
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.3
|
baseVersion=15.3
|
||||||
publishVersion=15.3.1
|
publishVersion=15.3.1
|
||||||
buildCount=0
|
buildCount=57
|
||||||
baseBetaVersion=15.3.2
|
baseBetaVersion=15.3.2
|
||||||
|
|||||||
@@ -4,11 +4,16 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.AbsListView;
|
import android.widget.AbsListView;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -16,19 +21,17 @@ import android.widget.Toolbar;
|
|||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
|
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
|
||||||
import cc.winboll.studio.mymessagemanager.R;
|
import cc.winboll.studio.mymessagemanager.R;
|
||||||
import cc.winboll.studio.mymessagemanager.activitys.SMSActivity;
|
|
||||||
import cc.winboll.studio.mymessagemanager.adapters.SMSArrayAdapter;
|
import cc.winboll.studio.mymessagemanager.adapters.SMSArrayAdapter;
|
||||||
import cc.winboll.studio.mymessagemanager.utils.AddressUtils;
|
import cc.winboll.studio.mymessagemanager.utils.AddressUtils;
|
||||||
import cc.winboll.studio.mymessagemanager.utils.SMSUtil;
|
import cc.winboll.studio.mymessagemanager.utils.SMSUtil;
|
||||||
import cc.winboll.studio.mymessagemanager.utils.ViewUtil;
|
import cc.winboll.studio.mymessagemanager.utils.ViewUtil;
|
||||||
|
import cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView;
|
||||||
import cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView;
|
import cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
public class SMSActivity extends BaseActivity {
|
public class SMSActivity extends BaseActivity {
|
||||||
public static String TAG = "SMSActivity";
|
public static String TAG = "SMSActivity";
|
||||||
|
|
||||||
public static final String ACTION_NOTIFY_SMS_CHANGED = "cc.winboll.studio.mymessagemanager.activitys.SMSActivity.ACTION_NOTIFY_SMS_CHANGED";
|
public static final String ACTION_NOTIFY_SMS_CHANGED = "cc.winboll.studio.mymessagemanager.activitys.SMSActivity.ACTION_NOTIFY_SMS_CHANGED";
|
||||||
|
|
||||||
public static final String EXTRA_PHONE = "Phone";
|
public static final String EXTRA_PHONE = "Phone";
|
||||||
final static int MSG_SET_FOCUS = 0;
|
final static int MSG_SET_FOCUS = 0;
|
||||||
|
|
||||||
@@ -36,10 +39,11 @@ public class SMSActivity extends BaseActivity {
|
|||||||
Toolbar mToolbar;
|
Toolbar mToolbar;
|
||||||
String mszPhoneTo;
|
String mszPhoneTo;
|
||||||
SMSArrayAdapter mSMSArrayAdapter;
|
SMSArrayAdapter mSMSArrayAdapter;
|
||||||
ScrollView mScrollView;
|
BottomPositionFixedScrollView mScrollView1;
|
||||||
EditText metSMSBody;
|
EditText metSMSBody;
|
||||||
SMSActivityBroadcastReceiver mSMSActivityBroadcastReceiver;
|
SMSActivityBroadcastReceiver mSMSActivityBroadcastReceiver;
|
||||||
Handler mSetFocusHandler;
|
Handler mSetFocusHandler;
|
||||||
|
private boolean isImeVisible = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -47,45 +51,90 @@ public class SMSActivity extends BaseActivity {
|
|||||||
setContentView(R.layout.activity_sms);
|
setContentView(R.layout.activity_sms);
|
||||||
|
|
||||||
initView();
|
initView();
|
||||||
mSetFocusHandler = new MyHandler(SMSActivity.this);
|
|
||||||
scrollScrollView();
|
scrollScrollView();
|
||||||
|
setupImeStatusListener();
|
||||||
|
|
||||||
// 每隔一定时间设置输入框获得焦点
|
// 新增:监听窗口加载完成,触发mScrollView1滚动到底部
|
||||||
//
|
setupScrollToBottomAfterWindowLoaded();
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(1500);
|
|
||||||
} catch (InterruptedException e) {}
|
|
||||||
Message message = mSetFocusHandler.obtainMessage(MSG_SET_FOCUS);
|
|
||||||
mSetFocusHandler.sendMessage(message);
|
|
||||||
}
|
|
||||||
}}.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// 新增:窗口加载完成后让mScrollView1滚动到底部
|
||||||
// 设置输入框获得焦点的类
|
private void setupScrollToBottomAfterWindowLoaded() {
|
||||||
//
|
final View rootView = findViewById(android.R.id.content);
|
||||||
static class MyHandler extends Handler {
|
// 监听根布局绘制完成(窗口加载完成的标志)
|
||||||
WeakReference<SMSActivity> mActivity;
|
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
MyHandler(SMSActivity activity) {
|
@Override
|
||||||
mActivity = new WeakReference<SMSActivity>(activity);
|
public void onGlobalLayout() {
|
||||||
}
|
// 滚动到底部
|
||||||
public void handleMessage(Message msg) {
|
mScrollView1.post(new Runnable() {
|
||||||
SMSActivity theActivity = mActivity.get();
|
@Override
|
||||||
switch (msg.what) {
|
public void run() {
|
||||||
case MSG_SET_FOCUS:
|
mScrollView1.fullScroll(ScrollView.FOCUS_DOWN);
|
||||||
theActivity.metSMSBody.setFocusable(true);
|
}
|
||||||
theActivity.metSMSBody.requestFocus();
|
});
|
||||||
break;
|
|
||||||
default:
|
// 移除监听,避免重复触发
|
||||||
break;
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
}
|
rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
super.handleMessage(msg);
|
} else {
|
||||||
}
|
rootView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupImeStatusListener() {
|
||||||
|
final View rootView = findViewById(android.R.id.content);
|
||||||
|
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
int rootViewHeight = rootView.getHeight();
|
||||||
|
int screenHeight = getResources().getDisplayMetrics().heightPixels;
|
||||||
|
int imeThreshold = dp2px(200);
|
||||||
|
|
||||||
|
boolean currentImeVisible = (screenHeight - rootViewHeight) > imeThreshold;
|
||||||
|
|
||||||
|
if (currentImeVisible != isImeVisible) {
|
||||||
|
isImeVisible = currentImeVisible;
|
||||||
|
setupScrollView1Height();
|
||||||
|
if (!isImeVisible) {
|
||||||
|
metSMSBody.clearFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
|
rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
|
} else {
|
||||||
|
rootView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||||
|
}
|
||||||
|
setupImeStatusListener();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private int dp2px(int dp) {
|
||||||
|
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static class MyHandler extends Handler {
|
||||||
|
WeakReference<SMSActivity> mActivity;
|
||||||
|
MyHandler(SMSActivity activity) {
|
||||||
|
mActivity = new WeakReference<SMSActivity>(activity);
|
||||||
|
}
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
SMSActivity theActivity = mActivity.get();
|
||||||
|
switch (msg.what) {
|
||||||
|
case MSG_SET_FOCUS:
|
||||||
|
theActivity.metSMSBody.setFocusable(true);
|
||||||
|
theActivity.metSMSBody.requestFocus();
|
||||||
|
theActivity.setupScrollView1Height();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
super.handleMessage(msg);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
@@ -94,135 +143,130 @@ public class SMSActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initView() {
|
void initView() {
|
||||||
// 发送端空号码退出
|
|
||||||
mszPhoneTo = getIntent().getStringExtra(EXTRA_PHONE);
|
mszPhoneTo = getIntent().getStringExtra(EXTRA_PHONE);
|
||||||
if (mszPhoneTo == null || mszPhoneTo.trim().equals("")) {
|
if (mszPhoneTo == null || mszPhoneTo.trim().equals("")) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化标题栏
|
mToolbar = (Toolbar) findViewById(R.id.activitysmsASupportToolbar1);
|
||||||
mToolbar = findViewById(R.id.activitysmsASupportToolbar1);
|
|
||||||
mToolbar.setSubtitle(getString(R.string.activity_name_smsinphone) + " < Phone : " + AddressUtils.getFormattedAddress(mszPhoneTo) + " >");
|
mToolbar.setSubtitle(getString(R.string.activity_name_smsinphone) + " < Phone : " + AddressUtils.getFormattedAddress(mszPhoneTo) + " >");
|
||||||
setActionBar(mToolbar);
|
setActionBar(mToolbar);
|
||||||
|
|
||||||
// 初始化滚动窗口
|
mScrollView1 = (BottomPositionFixedScrollView) findViewById(R.id.activitysmsScrollView1);
|
||||||
mScrollView = findViewById(R.id.activitysmsinphoneScrollView1);
|
|
||||||
|
|
||||||
// 初始化发送消息框
|
metSMSBody = (EditText) findViewById(R.id.viewsmssendpart1EditText1);
|
||||||
//Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame);
|
metSMSBody.setOnClickListener(new View.OnClickListener() {
|
||||||
metSMSBody = findViewById(R.id.viewsmssendpart1EditText1);
|
@Override
|
||||||
//metSMSBody.setBackground(drawableFrame);
|
public void onClick(View v) {
|
||||||
|
setupScrollView1Height();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
metSMSBody.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
|
setupScrollView1Height();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 初始化发送拉动控件
|
final AOHPCTCSeekBar aOHPCTCSeekBar = (AOHPCTCSeekBar) findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1);
|
||||||
final AOHPCTCSeekBar aOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1);
|
|
||||||
aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message));
|
aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message));
|
||||||
aOHPCTCSeekBar.setThumbOffset(20);
|
aOHPCTCSeekBar.setThumbOffset(20);
|
||||||
aOHPCTCSeekBar.setOnOHPCListener(
|
aOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() {
|
||||||
new AOHPCTCSeekBar.OnOHPCListener(){
|
@Override
|
||||||
@Override
|
public void onOHPCommit() {
|
||||||
public void onOHPCommit() {
|
sendSMS();
|
||||||
//Toast.makeText(getApplication(), "Send", Toast.LENGTH_SHORT).show();
|
}
|
||||||
sendSMS();
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 初始化提示框
|
TextView tvAOHPCTCSeekBarMSG = (TextView) findViewById(R.id.viewsmssendpart1TextView1);
|
||||||
TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1);
|
|
||||||
tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg);
|
tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg);
|
||||||
|
|
||||||
mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsinphoneListView1);
|
mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsSMSListViewForScrollView1);
|
||||||
|
|
||||||
// 准备数据
|
|
||||||
mSMSArrayAdapter = new SMSArrayAdapter(SMSActivity.this, mszPhoneTo);
|
mSMSArrayAdapter = new SMSArrayAdapter(SMSActivity.this, mszPhoneTo);
|
||||||
mlvSMS.setAdapter(mSMSArrayAdapter);
|
mlvSMS.setAdapter(mSMSArrayAdapter);
|
||||||
|
|
||||||
// 设置短信列表滚动到底部就取消已发送的通知消息
|
|
||||||
//
|
|
||||||
mlvSMS.setOnScrollListener(new AbsListView.OnScrollListener() {
|
mlvSMS.setOnScrollListener(new AbsListView.OnScrollListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
public void onScrollStateChanged(AbsListView view, int scrollState) {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
|
||||||
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
|
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
|
||||||
// 滑动到了底部
|
mSMSArrayAdapter.cancelMessageNotification();
|
||||||
mSMSArrayAdapter.cancelMessageNotification();
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
mSMSActivityBroadcastReceiver = new SMSActivityBroadcastReceiver();
|
mSMSActivityBroadcastReceiver = new SMSActivityBroadcastReceiver();
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
IntentFilter intentFilter = new IntentFilter(ACTION_NOTIFY_SMS_CHANGED);
|
||||||
intentFilter.addAction(ACTION_NOTIFY_SMS_CHANGED);
|
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mSMSActivityBroadcastReceiver, intentFilter);
|
LocalBroadcastManager.getInstance(this).registerReceiver(mSMSActivityBroadcastReceiver, intentFilter);
|
||||||
|
|
||||||
/*SMSView mSMSView = findViewById(R.id.viewsmssendSMSView1);
|
|
||||||
mSMSView.setSMSType(SMSView.SMSType.SEND);*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
private void setupScrollView1Height() {
|
||||||
// 更新信息列表
|
mScrollView1.postDelayed(new Runnable() {
|
||||||
//
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final ScrollView scrollView2 = (ScrollView) findViewById(R.id.activitysmsScrollView2);
|
||||||
|
final BottomPositionFixedScrollView scrollView1 = (BottomPositionFixedScrollView) findViewById(R.id.activitysmsScrollView1);
|
||||||
|
final View includeView = findViewById(R.id.activitysmsinclude1);
|
||||||
|
|
||||||
|
scrollView2.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int scrollView2Height = scrollView2.getHeight();
|
||||||
|
int includeHeight = includeView.getHeight();
|
||||||
|
int targetHeight = Math.max(scrollView2Height - includeHeight, 0);
|
||||||
|
|
||||||
|
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) scrollView1.getLayoutParams();
|
||||||
|
params.height = targetHeight;
|
||||||
|
scrollView1.setLayoutParams(params);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
public void updateSMSView() {
|
public void updateSMSView() {
|
||||||
mSMSArrayAdapter.reLoadSMSList(SMSActivity.this, mszPhoneTo);
|
mSMSArrayAdapter.reLoadSMSList(SMSActivity.this, mszPhoneTo);
|
||||||
mSMSArrayAdapter.notifyDataSetChanged();
|
mSMSArrayAdapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// 滚动消息文本框
|
|
||||||
//
|
|
||||||
void scrollScrollView() {
|
void scrollScrollView() {
|
||||||
|
ViewUtil.scrollScrollView(mScrollView1);
|
||||||
ViewUtil.scrollScrollView(mScrollView);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// 发送短信
|
|
||||||
//
|
|
||||||
void sendSMS() {
|
void sendSMS() {
|
||||||
// 空消息不发送
|
|
||||||
String szSMSBody = metSMSBody.getText().toString();
|
String szSMSBody = metSMSBody.getText().toString();
|
||||||
if (szSMSBody.equals("")) {
|
if (szSMSBody.equals("")) {
|
||||||
Toast.makeText(getApplication(), "没有消息内容可发送。", Toast.LENGTH_SHORT).show();
|
Toast.makeText(getApplication(), "没有消息内容可发送。", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送短信
|
|
||||||
if (SMSUtil.sendMessageByInterface2(this, mszPhoneTo, szSMSBody)) {
|
if (SMSUtil.sendMessageByInterface2(this, mszPhoneTo, szSMSBody)) {
|
||||||
metSMSBody.setText("");
|
metSMSBody.setText("");
|
||||||
new Handler().postDelayed(new Runnable(){
|
metSMSBody.clearFocus();
|
||||||
@Override
|
new Handler().postDelayed(new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
updateSMSView();
|
public void run() {
|
||||||
ViewUtil.scrollScrollView(mScrollView);
|
updateSMSView();
|
||||||
}
|
ViewUtil.scrollScrollView(mScrollView1);
|
||||||
}, 1000);
|
}
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SMSActivityBroadcastReceiver extends BroadcastReceiver {
|
class SMSActivityBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
public SMSActivityBroadcastReceiver() {}
|
||||||
public SMSActivityBroadcastReceiver() {
|
|
||||||
//LogUtils.d(TAG, "SMSActivityBroadcastReceiver()");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
switch (intent.getAction()) {
|
if (ACTION_NOTIFY_SMS_CHANGED.equals(intent.getAction())) {
|
||||||
case ACTION_NOTIFY_SMS_CHANGED :
|
updateSMSView();
|
||||||
//Toast.makeText(context, "ACTION_NOTIFY_SMS_CHANGED", Toast.LENGTH_SHORT).show();
|
ViewUtil.scrollScrollView(mScrollView1);
|
||||||
updateSMSView();
|
} else {
|
||||||
ViewUtil.scrollScrollView(mScrollView);
|
throw new IllegalStateException("Unexpected value: " + intent.getAction());
|
||||||
//LogUtils.d(TAG, "ACTION_NOTIFY_SMS_CHANGED");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Unexpected value: " + intent.getAction());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package cc.winboll.studio.mymessagemanager.views;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author ZhanGSKen&豆包大模型<zhangsken@188.com>
|
||||||
|
* @Date 2025/08/23 00:39
|
||||||
|
* @Describe 多级拉动响应自定义控件
|
||||||
|
*/
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
|
||||||
|
public class BottomPositionFixedScrollView extends ScrollView {
|
||||||
|
public static final String TAG = "BottomPositionFixedScrollView";
|
||||||
|
// 记录底部对应的内容绝对位置(即底部位置在内容中的y坐标,该位置需始终保持在视图底部)
|
||||||
|
private int mBottomContentY = 0;
|
||||||
|
// 标记是否是首次布局(避免初始加载误触发)
|
||||||
|
private boolean isFirstLayout = true;
|
||||||
|
|
||||||
|
public BottomPositionFixedScrollView(Context context) {
|
||||||
|
super(context);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BottomPositionFixedScrollView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BottomPositionFixedScrollView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
// 监听布局变化(高度改变时触发)
|
||||||
|
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
if (isFirstLayout) {
|
||||||
|
isFirstLayout = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 布局变化后,恢复底部位置
|
||||||
|
restoreBottomPosition();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重写滚动事件,记录“底部对应的内容绝对位置”
|
||||||
|
* (即当前视图底部边缘对应的内容y坐标,该坐标需始终保持在视图底部)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||||
|
super.onScrollChanged(l, t, oldl, oldt);
|
||||||
|
if (getChildCount() == 0) {
|
||||||
|
mBottomContentY = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容总高度
|
||||||
|
int contentHeight = getChildAt(0).getMeasuredHeight();
|
||||||
|
// 视图可视高度(自身高度)
|
||||||
|
int scrollViewHeight = getMeasuredHeight();
|
||||||
|
// 当前视图底部边缘对应的内容y坐标 = 顶部滚动距离(t) + 可视高度
|
||||||
|
// (该坐标就是“底部内容的绝对位置”,需始终保持在视图底部)
|
||||||
|
mBottomContentY = t + scrollViewHeight;
|
||||||
|
|
||||||
|
// 避免超过内容总高度(比如内容不足一屏时,底部最多到内容底部)
|
||||||
|
if (mBottomContentY > contentHeight) {
|
||||||
|
mBottomContentY = contentHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复底部位置:让原记录的“底部内容绝对位置”仍保持在视图底部
|
||||||
|
*/
|
||||||
|
private void restoreBottomPosition() {
|
||||||
|
if (getChildCount() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新的内容总高度
|
||||||
|
int newContentHeight = getChildAt(0).getMeasuredHeight();
|
||||||
|
// 新的视图可视高度
|
||||||
|
int newScrollViewHeight = getMeasuredHeight();
|
||||||
|
|
||||||
|
// 目标:让原mBottomContentY(底部内容绝对位置)仍位于视图底部
|
||||||
|
// 此时需要的顶部滚动距离 = mBottomContentY - 新的可视高度
|
||||||
|
int targetScrollY = mBottomContentY - newScrollViewHeight;
|
||||||
|
|
||||||
|
// 边界修正:
|
||||||
|
// 1. 不能小于0(避免滚动到负数位置)
|
||||||
|
// 2. 不能大于“最大可滚动距离”(内容高度 - 可视高度,避免超出内容范围)
|
||||||
|
int maxScrollY = Math.max(newContentHeight - newScrollViewHeight, 0);
|
||||||
|
targetScrollY = Math.max(targetScrollY, 0);
|
||||||
|
targetScrollY = Math.min(targetScrollY, maxScrollY);
|
||||||
|
|
||||||
|
// 滚动到目标位置,保持底部内容位置不变
|
||||||
|
smoothScrollTo(0, targetScrollY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部手动设置底部内容绝对位置(可选)
|
||||||
|
*/
|
||||||
|
public void setBottomContentY(int bottomContentY) {
|
||||||
|
if (getChildCount() == 0) {
|
||||||
|
mBottomContentY = bottomContentY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 限制不超过内容总高度
|
||||||
|
int contentHeight = getChildAt(0).getMeasuredHeight();
|
||||||
|
mBottomContentY = Math.min(bottomContentY, contentHeight);
|
||||||
|
restoreBottomPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前底部内容绝对位置(可选)
|
||||||
|
*/
|
||||||
|
public int getBottomContentY() {
|
||||||
|
return mBottomContentY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -10,36 +10,40 @@
|
|||||||
android:layout_height="@dimen/toolbar_height"
|
android:layout_height="@dimen/toolbar_height"
|
||||||
android:id="@+id/activitysmsASupportToolbar1"/>
|
android:id="@+id/activitysmsASupportToolbar1"/>
|
||||||
|
|
||||||
<RelativeLayout
|
<ScrollView
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
android:paddingBottom="10dp">
|
android:layout_weight="1.0"
|
||||||
|
android:id="@+id/activitysmsScrollView2">
|
||||||
|
|
||||||
<ScrollView
|
<LinearLayout
|
||||||
android:layout_alignParentTop="true"
|
android:orientation="vertical"
|
||||||
android:layout_above="@+id/activitysmsinclude1"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/activitysmsinphoneScrollView1"
|
android:id="@+id/activitysmsLinearLayout1">
|
||||||
android:layout_weight="1.0"
|
|
||||||
android:isScrollContainer="false">
|
|
||||||
|
|
||||||
<cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView
|
<cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="520dp"
|
||||||
|
android:isScrollContainer="false"
|
||||||
|
android:id="@+id/activitysmsScrollView1">
|
||||||
|
|
||||||
|
<cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/activitysmsSMSListViewForScrollView1"/>
|
||||||
|
|
||||||
|
</cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/view_smssend"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/activitysmsinphoneListView1"/>
|
android:id="@+id/activitysmsinclude1"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<include
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
layout="@layout/view_smssend"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/activitysmsinclude1"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,18 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="10dp">
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:id="@+id/viewsmssendpart1TextView1"/>
|
||||||
|
|
||||||
|
<cc.winboll.studio.libaes.views.AOHPCTCSeekBar
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/viewsmssendpart1AOHPCTCSeekBar1"/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
android:maxHeight="150dp"
|
android:maxHeight="150dp"
|
||||||
@@ -17,17 +29,6 @@
|
|||||||
android:id="@+id/viewsmssendpart1EditText1"
|
android:id="@+id/viewsmssendpart1EditText1"
|
||||||
android:background="@drawable/bg_frame"/>
|
android:background="@drawable/bg_frame"/>
|
||||||
|
|
||||||
<cc.winboll.studio.libaes.views.AOHPCTCSeekBar
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/viewsmssendpart1AOHPCTCSeekBar1"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:id="@+id/viewsmssendpart1TextView1"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,6 @@
|
|||||||
<string name="text_appsettings">应用设置</string>
|
<string name="text_appsettings">应用设置</string>
|
||||||
<string name="text_ttsplaydelaytimes">TTS播放延迟时间(秒):</string>
|
<string name="text_ttsplaydelaytimes">TTS播放延迟时间(秒):</string>
|
||||||
<string name="msg_newsms">接收到新的消息。</string>
|
<string name="msg_newsms">接收到新的消息。</string>
|
||||||
<string name="msg_100sendmsg">>>>拉图标动到 100% 以发送信息。>>></string>
|
<string name="msg_100sendmsg">>>>拉动到100%可发信息>>></string>
|
||||||
<string name="msg_100applysettings">>>>拉图标动到 100% 应用设置。>>></string>
|
<string name="msg_100applysettings">>>>拉动到100%可应用设置>>></string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user