MeasureSpec学习—对Integer.MAX_VALUE >> 2的认识

本文详细介绍了MeasureSpec在自定义View和ViewGroup中的作用,包括其大小模式及其内部实现方式,并提供了MeasureSpec工具类的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在自定义ViewViewGroup的时候,我们经常会遇到int型的MeasureSpec来表示一个组件的大小,这个变量里面不仅有组件的尺寸大小,还有大小的模式。

这个大小的模式,有点难以理解。在系统中组件的大小模式有三种:

1.精确模式(MeasureSpec.EXACTLY

在这种模式下,尺寸的值是多少,那么这个组件的长或宽就是多少。

2.最大模式(MeasureSpec.AT_MOST

这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小。

3.未指定模式(MeasureSpec.UNSPECIFIED

这个就是说,当前组件,可以随便用空间,不受限制。

    可能有很多人想不通,一个int型整数怎么可以表示两个东西(大小模式和大小的值),一个int类型我们知道有32位。而模式有三种,要表示三种状  态,至少得2位二进制位。于是系统采用了最高的2位表示模式。如图:

最高两位是00的时候表示"未指定模式"。即MeasureSpec.UNSPECIFIED

最高两位是01的时候表示"'精确模式"。即MeasureSpec.EXACTLY

最高两位是10的时候表示"最大模式"。即MeasureSpec.AT_MOST

很多人一遇到位操作头就大了,为了操作简便,于是系统给我提供了一个MeasureSpec工具类。

这个工具类有四个方法和三个常量(上面所示)供我们使用:

 

//这个是由我们给出的尺寸大小和模式生成一个包含这两个信息的int变量,这里这个模式这个参数,传三个常量中的一个。

public static int makeMeasureSpec(int size, int mode)

 

//这个是得到这个变量中表示的模式信息,将得到的值与三个常量进行比较。

public static int getMode(int measureSpec)

 

//这个是得到这个变量中表示的尺寸大小的值。

public static int getSize(int measureSpec)

 

//把这个变量里面的模式和大小组成字符串返回来,方便打日志

 public static String toString(int measureSpec)

 

package com.example.testrecyclerview; import android.os.Bundle; import androidx.activity.EdgeToEdge; import androidx.appcompat.app.AppCompatActivity; import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.example.testrecyclerview.databinding.ActivityMainBinding; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { List<String> uri = new ArrayList<>(); private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); EdgeToEdge.enable(this); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); return insets; }); uri.add("https://api.wakingtracker.fun/storage/images/cc8f7b3addfdc7751bb26ddcb074b7e3.png"); uri.add("https://api.wakingtracker.fun/storage/images/da2c76f0cf56606ef98e554eff48c6d0.png"); uri.add("https://api.wakingtracker.fun/storage/images/da2c76f0cf56606ef98e554eff48c6d0.png"); uri.add("https://api.wakingtracker.fun/storage/images/da2c76f0cf56606ef98e554eff48c6d0.png"); uri.add("https://api.wakingtracker.fun/storage/images/da2c76f0cf56606ef98e554eff48c6d0.png"); LinearLayoutManager lm = new LinearLayoutManager(this, RecyclerView.VERTICAL, false) { @Override public boolean isAutoMeasureEnabled() { return true; // 强制 wrap_content 下测量全部子项 } @Override public boolean canScrollVertically() { return false; // 禁用自身滚动 } }; binding.recycler.setLayoutManager(lm); binding.recycler.setNestedScrollingEnabled(false); binding.recycler.setLayoutManager(lm); binding.recycler.setAdapter(new PhotoAdapter(uri)); binding.recycler.setHasFixedSize(false); } }package com.example.testrecyclerview; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import androidx.recyclerview.widget.RecyclerView; // 禁止RecyclerView滑动 public class NonScrollRecyclerView extends RecyclerView { public NonScrollRecyclerView(Context context) { super(context); } public NonScrollRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public NonScrollRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { return false; // 拦截触摸事件但不处理 } @Override protected void onMeasure(int widthSpec, int heightSpec) { // 根据内容动态计算高度 int expandSpec = MeasureSpec.makeMeasureSpec( Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthSpec, expandSpec); } }无法解决,还是显示一张itme
06-12
Android页面顶部有tab标签,每个tab标签有对应的列表数据,但是加载数据后,列表数据不能上下滚动,activity代码: public class ActivityTaskCenter extends Activity { private ImageView imgBack; private Button btnRefresh; private TextView tvTitle; private LinearLayout tabLayout; private HorizontalScrollView tabScrollView; private SwipeMenuListView taskListView; private List<Map<String,Object>> dataList = new ArrayList<>(); private final static int SCANNIN_GREQUEST_ORDER = 1000; private String userid = ""; private String whseid = ""; private int currentTab = 0; private TaskCenterAdapter taskCenterAdapter = null; public ActivityTaskCenter.TaskCenterAdapter getMyActivityTaskCenter() { return taskCenterAdapter; } public List<Map<String, Object>> getTaskCenterList() { return dataList; } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_task); imgBack = this.findViewById(R.id.id_title_btnBack); btnRefresh = this.findViewById(R.id.id_title_btnRefrush); tvTitle = this.findViewById(R.id.id_title_tip); tabScrollView = findViewById(R.id.tabScrollView); tabLayout = findViewById(R.id.tabLayout); taskListView = findViewById(R.id.id_taskcenter_listview); initView(); // 初始化标签栏 initTabs(); initEvent(); // 延迟加载确保布局已完成 taskListView.post(() -> loadData(0)); taskListView.setScrollContainer(true); taskListView.requestLayout(); } private void initView(){ try{ tvTitle.setText("任务中心"); btnRefresh.setVisibility(View.GONE); //初始化等待界面 Config.m_pDoalog = new ProgressDialog(ActivityTaskCenter.this); Config.m_pDoalog.setProgressStyle(ProgressDialog.STYLE_SPINNER); userid = SharedPreferencesUtil.GetData(getApplication(), "username", "").toString(); whseid = SharedPreferencesUtil.GetData(getApplication(), "whseid", "").toString(); taskCenterAdapter = new TaskCenterAdapter(); taskListView.setAdapter(taskCenterAdapter); taskListView.setNestedScrollingEnabled(true); }catch (Exception e){ e.printStackTrace(); } } private void initTabs() { String[] tabTitles = {"未领取", "已领取", "已完成"}; int activeColor = getResources().getColor(R.color.color_yelloworange); int inactiveColor = getResources().getColor(android.R.color.black); for (int i = 0; i < tabTitles.length; i++) { TextView tab = new TextView(this); tab.setTag(i); tab.setText(tabTitles[i]); tab.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); tab.setGravity(Gravity.CENTER); tab.setPadding(32, 16, 32, 16); // 设置初始状态 if (i == currentTab) { tab.setBackgroundColor(getResources().getColor(android.R.color.white)); tab.setTextColor(activeColor); tab.getPaint().setFakeBoldText(true); } else { tab.setBackgroundColor(getResources().getColor(R.color.color_yelloworange)); tab.setTextColor(inactiveColor); } LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); tab.setLayoutParams(params); // 设置点击监听 tab.setOnClickListener(v -> { int tabIndex = (int) v.getTag(); switchTab(tabIndex); loadData(tabIndex); currentTab = tabIndex; }); tabLayout.addView(tab); } } private void switchTab(int tabIndex) { // 更新UI样式 for (int i = 0; i < tabLayout.getChildCount(); i++) { TextView tab = (TextView) tabLayout.getChildAt(i); if (i == tabIndex) { tab.setBackgroundColor(getResources().getColor(android.R.color.white)); tab.setTextColor(getResources().getColor(R.color.color_yelloworange)); tab.getPaint().setFakeBoldText(true); } else { tab.setBackgroundColor(getResources().getColor(R.color.color_yelloworange)); tab.setTextColor(getResources().getColor(android.R.color.white)); tab.getPaint().setFakeBoldText(false); } } // 确保选中的标签可见 tabScrollView.smoothScrollTo(tabLayout.getChildAt(tabIndex).getLeft(), 0); currentTab = tabIndex; } private int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,getResources().getDisplayMetrics()); } private void initEvent(){ try { imgBack.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { ActivityTaskCenter.this.finish(); } }); } catch (Exception e) { throw new RuntimeException(e); } } private final Handler TaskCenterHandle = new Handler(new Handler.Callback() { @Override public boolean handleMessage(@NonNull Message msg) { try{ switch (msg.what){ case SCANNIN_GREQUEST_ORDER: Document doc = new Document(new Element("NewDataSet")); Element rootEle = doc.getRootElement(); Element licUserEle = new Element("RecCheck"); licUserEle.addContent(new Element("userid").addContent(userid)); licUserEle.addContent(new Element("whseid").addContent(whseid)); rootEle.addContent(licUserEle); PostWebservices.webSend(ActivityTaskCenter.this,new HandlerMsg(ActivityTaskCenter.this),47, DomUtil.doc2xmlStr(doc)); break; } }catch (Exception e){ e.printStackTrace(); Toast.makeText(getApplicationContext(),e.getMessage(),Toast.LENGTH_SHORT).show(); } return true; } }); private void loadData(int tabIndex) { dataList.clear(); switch (tabIndex) { case 0: // 未领取 getLoadData(47); break; case 1: // 已领取 getLoadData(48); break; case 2: // 已完成 getLoadData(49); break; } } public void refresh(){ getLoadData(currentTab); } public void playErrorSound(Context context) { MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.beep); if (mediaPlayer != null) { mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mp.release(); // 播放完成后释放资源 } }); mediaPlayer.start(); } } public class TaskCenterAdapter extends BaseAdapter { @Override public int getCount() { return dataList == null ? 0 : dataList.size(); } @Override public Object getItem(int i) { return dataList.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView == null){ convertView = View.inflate(getApplicationContext(),R.layout.item_listview4taskcenter,null); new ActivityTaskCenter.TaskCenterAdapter.ViewHolderForOutBound(convertView); } ViewHolderForOutBound holder = (ViewHolderForOutBound) convertView.getTag(); final Map<String, Object> item = (Map<String, Object>) getItem(position); holder.task_orderno.setText(item.get("receiptkey").toString()); holder.task_adddate.setText(item.get("adddate").toString()); holder.task_tasktype.setText(item.get("task_type").toString()); holder.task_status.setText(item.get("status").toString()); holder.task_customer.setText(item.get("company").toString()); holder.task_pre_qty.setText(item.get("pre_qty").toString()); holder.task_goods_count.setText(item.get("goods_count").toString()); holder.btnReceive.setTag(position); convertView.setFocusable(true); convertView.setClickable(true); return convertView; } class ViewHolderForOutBound{ private TextView task_orderno; private TextView task_adddate; private TextView task_tasktype; private TextView task_status; private TextView task_customer; private TextView task_pre_qty; private TextView task_goods_count; private Button btnReceive; public ViewHolderForOutBound(View view){ task_orderno = (TextView) view.findViewById(R.id.id_taskcenter_receiptkey); task_adddate = (TextView) view.findViewById(R.id.id_taskcenter_adddate); task_tasktype = (TextView) view.findViewById(R.id.id_taskcenter_tasktype); task_status = (TextView) view.findViewById(R.id.id_taskcenter_status); task_customer = (TextView) view.findViewById(R.id.id_taskcenter_customer); task_pre_qty = (TextView) view.findViewById(R.id.id_taskcenter_pre_qty); task_goods_count = (TextView) view.findViewById(R.id.id_taskcenter_goods_count); btnReceive = (Button) view.findViewById(R.id.btn_task_claim); btnReceive.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view) { int position = (int) view.getTag(); // 从 tag 中获取 position Map<String, Object> item = (Map<String, Object>) dataList.get(position); String receiptKey = item.get("receiptkey").toString(); String task_type = item.get("task_type").toString(); int msgwhat = 50; if(task_type.equals("验货任务")){ msgwhat = 50; } else if (task_type.equals("拣货任务")) { msgwhat = 51; }else if (task_type.equals("发货任务")) { msgwhat = 52; } Config.m_pDoalog.setMessage("请稍等..."); Config.m_pDoalog.setIndeterminate(false); Config.m_pDoalog.setCancelable(false); Config.m_pDoalog.show(); Document doc = new Document(new Element("NewDataSet")); Element rootEle = doc.getRootElement(); Element licUserEle = new Element("RecCheck"); licUserEle.addContent(new Element("userid").addContent(userid)); licUserEle.addContent(new Element("whseid").addContent(whseid)); licUserEle.addContent(new Element("orderkey").addContent(receiptKey)); rootEle.addContent(licUserEle); PostWebservices.webSend(ActivityTaskCenter.this,new HandlerMsg(ActivityTaskCenter.this),msgwhat, DomUtil.doc2xmlStr(doc)); } }); view.setTag(this); } } } public void showData(List<Map<String, Object>> dataList){ this.dataList = dataList; taskCenterAdapter.notifyDataSetChanged(); } public void getLoadData(int msgwhat){ Config.m_pDoalog.setMessage("请稍等..."); Config.m_pDoalog.setIndeterminate(false); Config.m_pDoalog.setCancelable(false); Config.m_pDoalog.show(); Document doc = new Document(new Element("NewDataSet")); Element rootEle = doc.getRootElement(); Element licUserEle = new Element("RecCheck"); licUserEle.addContent(new Element("userid").addContent(userid)); licUserEle.addContent(new Element("whseid").addContent(whseid)); rootEle.addContent(licUserEle); PostWebservices.webSend(ActivityTaskCenter.this,new HandlerMsg(ActivityTaskCenter.this),msgwhat, DomUtil.doc2xmlStr(doc)); } public void setCloseProDialog(){ Config.m_pDoalog.hide(); } } activity_task代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="#F5F5F5"> <!-- 固定顶部的标签栏 --> <HorizontalScrollView android:id="@+id/tabScrollView" android:layout_width="match_parent" android:layout_height="40dp" android:fillViewport="true" android:scrollbars="none" android:background="@color/color_yelloworange"> <LinearLayout android:id="@+id/tabLayout" android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="horizontal" /> </HorizontalScrollView> <com.likelic.wmsassistantbyadp.baoyz.swipemenulistview.SwipeMenuListView.SwipeMenuListView android:id="@+id/id_taskcenter_listview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:divider="#EEEEEE" android:dividerHeight="2px" android:scrollbars="vertical" android:nestedScrollingEnabled="true"/> </LinearLayout>
最新发布
07-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值