短信发送窗口UI优化
This commit is contained in:
		| @@ -1,8 +1,8 @@ | ||||
| #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 | ||||
| libraryProject= | ||||
| baseVersion=15.3 | ||||
| publishVersion=15.3.1 | ||||
| buildCount=0 | ||||
| buildCount=57 | ||||
| baseBetaVersion=15.3.2 | ||||
|   | ||||
| @@ -4,11 +4,16 @@ import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.IntentFilter; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import android.view.View; | ||||
| import android.view.ViewTreeObserver; | ||||
| import android.view.inputmethod.InputMethodManager; | ||||
| import android.widget.AbsListView; | ||||
| import android.widget.EditText; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| @@ -16,19 +21,17 @@ import android.widget.Toolbar; | ||||
| import androidx.localbroadcastmanager.content.LocalBroadcastManager; | ||||
| import cc.winboll.studio.libaes.views.AOHPCTCSeekBar; | ||||
| 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.utils.AddressUtils; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.ViewUtil; | ||||
| import cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView; | ||||
| import cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView; | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| public class SMSActivity extends BaseActivity { | ||||
|     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 EXTRA_PHONE = "Phone"; | ||||
|     final static int MSG_SET_FOCUS = 0; | ||||
|  | ||||
| @@ -36,10 +39,11 @@ public class SMSActivity extends BaseActivity { | ||||
|     Toolbar mToolbar; | ||||
|     String mszPhoneTo; | ||||
|     SMSArrayAdapter mSMSArrayAdapter; | ||||
|     ScrollView mScrollView; | ||||
|     BottomPositionFixedScrollView mScrollView1; | ||||
|     EditText metSMSBody; | ||||
|     SMSActivityBroadcastReceiver mSMSActivityBroadcastReceiver; | ||||
|     Handler mSetFocusHandler; | ||||
|     private boolean isImeVisible = false; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
| @@ -47,45 +51,90 @@ public class SMSActivity extends BaseActivity { | ||||
|         setContentView(R.layout.activity_sms); | ||||
|  | ||||
|         initView(); | ||||
| 		mSetFocusHandler = new MyHandler(SMSActivity.this); | ||||
|         scrollScrollView(); | ||||
|         setupImeStatusListener(); | ||||
|  | ||||
|         // 每隔一定时间设置输入框获得焦点 | ||||
|         // | ||||
|         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滚动到底部 | ||||
|         setupScrollToBottomAfterWindowLoaded(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 设置输入框获得焦点的类 | ||||
| 	// | ||||
| 	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(); | ||||
|                     break; | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|             super.handleMessage(msg); | ||||
|         } | ||||
| 	} | ||||
|     // 新增:窗口加载完成后让mScrollView1滚动到底部 | ||||
|     private void setupScrollToBottomAfterWindowLoaded() { | ||||
|         final View rootView = findViewById(android.R.id.content); | ||||
|         // 监听根布局绘制完成(窗口加载完成的标志) | ||||
|         rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { | ||||
| 				@Override | ||||
| 				public void onGlobalLayout() { | ||||
| 					// 滚动到底部 | ||||
| 					mScrollView1.post(new Runnable() { | ||||
| 							@Override | ||||
| 							public void run() { | ||||
| 								mScrollView1.fullScroll(ScrollView.FOCUS_DOWN); | ||||
| 							} | ||||
| 						}); | ||||
|  | ||||
| 					// 移除监听,避免重复触发 | ||||
| 					if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { | ||||
| 						rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); | ||||
| 					} 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 | ||||
|     protected void onDestroy() { | ||||
| @@ -94,135 +143,130 @@ public class SMSActivity extends BaseActivity { | ||||
|     } | ||||
|  | ||||
|     void initView() { | ||||
|         // 发送端空号码退出 | ||||
|         mszPhoneTo = getIntent().getStringExtra(EXTRA_PHONE); | ||||
|         if (mszPhoneTo == null || mszPhoneTo.trim().equals("")) { | ||||
|             finish(); | ||||
|         } | ||||
|  | ||||
|         // 初始化标题栏 | ||||
|         mToolbar = findViewById(R.id.activitysmsASupportToolbar1); | ||||
|         mToolbar = (Toolbar) findViewById(R.id.activitysmsASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.activity_name_smsinphone) + " < Phone : " + AddressUtils.getFormattedAddress(mszPhoneTo) + " >"); | ||||
|         setActionBar(mToolbar); | ||||
|  | ||||
|         // 初始化滚动窗口 | ||||
|         mScrollView = findViewById(R.id.activitysmsinphoneScrollView1); | ||||
|         mScrollView1 = (BottomPositionFixedScrollView) findViewById(R.id.activitysmsScrollView1); | ||||
|  | ||||
|         // 初始化发送消息框 | ||||
|         //Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame); | ||||
|         metSMSBody = findViewById(R.id.viewsmssendpart1EditText1); | ||||
|         //metSMSBody.setBackground(drawableFrame); | ||||
|         metSMSBody = (EditText) findViewById(R.id.viewsmssendpart1EditText1); | ||||
|         metSMSBody.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					setupScrollView1Height(); | ||||
| 				} | ||||
| 			}); | ||||
|         metSMSBody.setOnFocusChangeListener(new View.OnFocusChangeListener() { | ||||
| 				@Override | ||||
| 				public void onFocusChange(View v, boolean hasFocus) { | ||||
| 					setupScrollView1Height(); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         // 初始化发送拉动控件 | ||||
|         final AOHPCTCSeekBar aOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1); | ||||
|         final AOHPCTCSeekBar aOHPCTCSeekBar = (AOHPCTCSeekBar) findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1); | ||||
|         aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message)); | ||||
|         aOHPCTCSeekBar.setThumbOffset(20); | ||||
|         aOHPCTCSeekBar.setOnOHPCListener( | ||||
|             new AOHPCTCSeekBar.OnOHPCListener(){ | ||||
|                 @Override | ||||
|                 public void onOHPCommit() { | ||||
|                     //Toast.makeText(getApplication(), "Send", Toast.LENGTH_SHORT).show(); | ||||
|                     sendSMS(); | ||||
|                 } | ||||
|             }); | ||||
|         aOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() { | ||||
| 				@Override | ||||
| 				public void onOHPCommit() { | ||||
| 					sendSMS(); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         // 初始化提示框 | ||||
|         TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1); | ||||
|         TextView tvAOHPCTCSeekBarMSG = (TextView) findViewById(R.id.viewsmssendpart1TextView1); | ||||
|         tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg); | ||||
|  | ||||
|         mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsinphoneListView1); | ||||
|  | ||||
|         // 准备数据 | ||||
|         mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsSMSListViewForScrollView1); | ||||
|         mSMSArrayAdapter = new SMSArrayAdapter(SMSActivity.this, mszPhoneTo); | ||||
|         mlvSMS.setAdapter(mSMSArrayAdapter); | ||||
|  | ||||
|         // 设置短信列表滚动到底部就取消已发送的通知消息 | ||||
|         // | ||||
|         mlvSMS.setOnScrollListener(new AbsListView.OnScrollListener() { | ||||
|                 @Override | ||||
|                 public void onScrollStateChanged(AbsListView view, int scrollState) { | ||||
|                 } | ||||
| 				@Override | ||||
| 				public void onScrollStateChanged(AbsListView view, int scrollState) {} | ||||
|  | ||||
|                 @Override | ||||
|                 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { | ||||
|                     if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) { | ||||
|                         // 滑动到了底部 | ||||
|                         mSMSArrayAdapter.cancelMessageNotification(); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
| 				@Override | ||||
| 				public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { | ||||
| 					if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) { | ||||
| 						mSMSArrayAdapter.cancelMessageNotification(); | ||||
| 					} | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         mSMSActivityBroadcastReceiver = new SMSActivityBroadcastReceiver(); | ||||
|         IntentFilter intentFilter = new IntentFilter(); | ||||
|         intentFilter.addAction(ACTION_NOTIFY_SMS_CHANGED); | ||||
|         IntentFilter intentFilter = new IntentFilter(ACTION_NOTIFY_SMS_CHANGED); | ||||
|         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() { | ||||
|         mSMSArrayAdapter.reLoadSMSList(SMSActivity.this, mszPhoneTo); | ||||
|         mSMSArrayAdapter.notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 滚动消息文本框 | ||||
|     // | ||||
|     void scrollScrollView() { | ||||
|  | ||||
|         ViewUtil.scrollScrollView(mScrollView); | ||||
|  | ||||
|         ViewUtil.scrollScrollView(mScrollView1); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 发送短信 | ||||
|     // | ||||
|     void sendSMS() { | ||||
|         // 空消息不发送 | ||||
|         String szSMSBody = metSMSBody.getText().toString(); | ||||
|         if (szSMSBody.equals("")) { | ||||
|             Toast.makeText(getApplication(), "没有消息内容可发送。", Toast.LENGTH_SHORT).show(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // 发送短信 | ||||
|         if (SMSUtil.sendMessageByInterface2(this, mszPhoneTo, szSMSBody)) { | ||||
|             metSMSBody.setText(""); | ||||
|             new Handler().postDelayed(new Runnable(){ | ||||
|                     @Override | ||||
|                     public void run() { | ||||
|                         updateSMSView(); | ||||
|                         ViewUtil.scrollScrollView(mScrollView); | ||||
|                     } | ||||
|                 }, 1000); | ||||
|             metSMSBody.clearFocus(); | ||||
|             new Handler().postDelayed(new Runnable() { | ||||
| 					@Override | ||||
| 					public void run() { | ||||
| 						updateSMSView(); | ||||
| 						ViewUtil.scrollScrollView(mScrollView1); | ||||
| 					} | ||||
| 				}, 1000); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     class SMSActivityBroadcastReceiver extends BroadcastReceiver { | ||||
|  | ||||
|         public SMSActivityBroadcastReceiver() { | ||||
|             //LogUtils.d(TAG, "SMSActivityBroadcastReceiver()"); | ||||
|         } | ||||
|         public SMSActivityBroadcastReceiver() {} | ||||
|  | ||||
|         @Override | ||||
|         public void onReceive(Context context, Intent intent) { | ||||
|             switch (intent.getAction()) { | ||||
|                 case ACTION_NOTIFY_SMS_CHANGED : | ||||
|                     //Toast.makeText(context, "ACTION_NOTIFY_SMS_CHANGED", Toast.LENGTH_SHORT).show(); | ||||
|                     updateSMSView(); | ||||
|                     ViewUtil.scrollScrollView(mScrollView); | ||||
|                     //LogUtils.d(TAG, "ACTION_NOTIFY_SMS_CHANGED"); | ||||
|                     break; | ||||
|                 default: | ||||
|                     throw new IllegalStateException("Unexpected value: " + intent.getAction()); | ||||
|             if (ACTION_NOTIFY_SMS_CHANGED.equals(intent.getAction())) { | ||||
|                 updateSMSView(); | ||||
|                 ViewUtil.scrollScrollView(mScrollView1); | ||||
|             } else { | ||||
|                 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:id="@+id/activitysmsASupportToolbar1"/> | ||||
|  | ||||
| 	<RelativeLayout | ||||
| 		android:orientation="vertical" | ||||
| 	<ScrollView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="match_parent" | ||||
| 		android:paddingBottom="10dp"> | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:id="@+id/activitysmsScrollView2"> | ||||
|  | ||||
| 		<ScrollView | ||||
| 			android:layout_alignParentTop="true" | ||||
| 			android:layout_above="@+id/activitysmsinclude1" | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="0dp" | ||||
| 			android:id="@+id/activitysmsinphoneScrollView1" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:isScrollContainer="false"> | ||||
| 			android:layout_height="match_parent" | ||||
| 			android:id="@+id/activitysmsLinearLayout1"> | ||||
|  | ||||
| 			<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_height="wrap_content" | ||||
| 				android:id="@+id/activitysmsinphoneListView1"/> | ||||
| 				android:id="@+id/activitysmsinclude1"/> | ||||
| 			 | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		</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> | ||||
| 	</ScrollView> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,18 @@ | ||||
| 	android:layout_height="wrap_content" | ||||
| 	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 | ||||
|         android:scrollbars="vertical" | ||||
|         android:maxHeight="150dp" | ||||
| @@ -17,17 +29,6 @@ | ||||
| 		android:id="@+id/viewsmssendpart1EditText1" | ||||
| 		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> | ||||
|  | ||||
|   | ||||
| @@ -41,6 +41,6 @@ | ||||
|     <string name="text_appsettings">应用设置</string> | ||||
|     <string name="text_ttsplaydelaytimes">TTS播放延迟时间(秒):</string> | ||||
|     <string name="msg_newsms">接收到新的消息。</string> | ||||
|     <string name="msg_100sendmsg">>>>拉图标动到 100% 以发送信息。>>></string> | ||||
|     <string name="msg_100applysettings">>>>拉图标动到 100% 应用设置。>>></string> | ||||
|     <string name="msg_100sendmsg">>>>拉动到100%可发信息>>></string> | ||||
|     <string name="msg_100applysettings">>>>拉动到100%可应用设置>>></string> | ||||
| </resources> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen