【发布时间】:2017-11-02 12:04:13
【问题描述】:
我正在创建自定义 LinearLayout 以用作 RecyclerView 中的行项目。有两个片段使用两个 RecyclerView 和两个适配器,使用 XML 定义的一个布局。在调整行项大小时,两个片段都显示出相同的异常行为,但这是可以理解的,因为它们使用相同的布局文件和几乎相同的稍作修改的适配器/片段代码。
这是布局文件 pool_layout.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="vertical"
android:paddingLeft="@dimen/betPool_padding_horizontal"
android:paddingRight="@dimen/betPool_padding_horizontal"
android:paddingTop="@dimen/betPool_padding_vertical"
android:layout_margin="@dimen/courseRace_margin"
android:id="@+id/stakepool_background">
<TextView
android:id="@+id/stakepool_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<TextView
android:id="@+id/stakepool_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="@dimen/betPool_text_size"
/>
</LinearLayout>
包含 LinearLayout 的高度设置为 100dp,宽度设置为 match_parent,但 RecyclerView 显示的视图具有不同的宽度,每次重绘视图时都会发生变化。
这是 LinearLayout 的父级,片段的 RecyclerView 由 XML 定义:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/pools_frag"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/brb_cyan"
tools:context="com.ineda.terminal.fragments.pools.PoolsFragment">
<!-- TODO: Update blank fragment layout -->
<android.support.v7.widget.RecyclerView
android:id="@+id/pools_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
<TextView
android:id="@+id/overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.5"
android:background="@color/md_grey_200"
android:clickable="true"
android:gravity="center"
android:textColor="@color/md_white_1000"
android:visibility="gone" />
</FrameLayout>
此宽度也设置为 match_parent,它的父级(不包括在内)由具有相对布局的 main_activity XML 定义,因此视图宽度应该按照定义的片段宽度调整大小在 main_activity 减去边距等,但事实并非如此。
public class PoolsFragment extends Fragment {
public static final String POOL_SELECTED = "com.ineda.terminal.fragments.ppol.POOL_SELECTED";
private Context context;
private RecyclerView mRecyclerView;
private PoolsAdapter mAdapter;
private List<Pool> poolList = new ArrayList<>();
private Pool currentPool;
private TextView overlay;
private Pool previousSelection;
public PoolsFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
context = getContext();
// Inflate the layout for this fragment
return inflater.inflate(R.layout.pools_fragment, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAdapter = new PoolsAdapter(poolList, context);
overlay = view.findViewById(R.id.overlay);
overlay.setOnClickListener(new View.OnClickListener() {
mRecyclerView = (RecyclerView) view.findViewById(R.id.pools_recyclerView);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
}
片段代码,以防您认为它相关但我怀疑它不相关。
适配器代码:
public class PoolsAdapter extends RecyclerView.Adapter<PoolsAdapter.holder> {
private static OnPoolClickListener OnPoolClickListener;
private List<Pool> pools;
private Context context;
private View previousSelectedPool;
private Pool currentPool;
private boolean initialised;
public PoolsAdapter(List<Pool> list, Context context) {
this.pools = list;
this.context = context;
}
@Override
public holder onCreateViewHolder(ViewGroup parent, int viewType) {
return new holder(new StakePoolButton(context));
}
@Override
public void onBindViewHolder(final holder holder, final int position) {
currentPool = pools.get(position);
holder.button.getButtonText().setText(pools.get(position).code);
if (!initialised) {
if (position == 0) {
OnPoolClickListener.onPoolClick(currentPool);
}
initialised = true;
}
if(currentPool.getStates() == null){
currentPool.setStates(ButtonStates.UNSELECTED);
}
switch (currentPool.getStates()){
case UNSELECTED:
holder.button.colourAsDeselected();
break;
case SELECTED:
holder.button.colourAsSelected();
break;
}
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
holder.button.setLayoutParams(params);
}
public class holder extends RecyclerView.ViewHolder implements View.OnClickListener {
StakePoolButton button;
public holder(StakePoolButton view) {
super(view);
view.setOnClickListener(this);
button = view;
}
我强制布局在适配器级别调整自身大小,因为这是一种让它至少看起来不错的 hacky 方式,但这不会长期有效,特别是如果应用程序要进入多个设备或需要调整大小等。这是通过 LinearLayout.LayoutParams 在布局膨胀后强制布局宽度为 wrap_content 完成的。如果我然后进入 XML 并使自定义布局的高度更小,则其中包含的文本不会缩小以匹配,这意味着事情不合时宜。
这终于是自定义线性布局本身,虽然如果是问题我会感到惊讶:
public class StakePoolButton extends LinearLayout { //button used for both the stake and pool fragments.
private TextView buttonText;
private LinearLayout stakePoolBackground;
private Context context;
boolean stake; //false means pool
private Typeface font;
public StakePoolButton(Context context) {
super(context);
init(context);
}
public StakePoolButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public StakePoolButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void init(Context context){
LayoutInflater.from(getContext()).inflate(
R.layout.pool_layout, this);
this.context = context;
this.font = Typeface.createFromAsset(context.getAssets(), "fonts/Cabin_Regular.ttf");
buttonText = findViewById(R.id.stakepool_name);
buttonText.setTypeface(font);
stakePoolBackground = findViewById(R.id.stakepool_background);
}
public void setData(Pool pool){
buttonText.setText(pool.code);
this.stake = false;
}
public void setData(Stake stake){
buttonText.setText(String.valueOf("£" + stake.getStake()));
this.stake = true;
}
我有其他自定义 LinearLayouts 可以完美运行,并且可以通过更改包含布局的宽度和高度值进行适当调整,但无论出于何种原因,这个都不起作用。
edit:在左边我们有预期的行为,这是通过在通货膨胀后设置 LayoutParams 来强制的。在右边,我们有在通货膨胀后没有被强迫的行为。宽度都是可变的,并且每次重新加载视图时都会改变。
【问题讨论】:
-
发布预期和实际的屏幕截图。
-
@azizbekian 完成 :)
-
作为测试,尝试将两个 RecyclerView 放入一个 Fragment。 RecyclerView 的布局父级应该是 LinearLayout,方向设置为水平。给两个 RecyclerView 的权重“0.5dp”以强制它们各自占据屏幕的一半。看看你是否得到了你期望的恒定宽度尺寸。另外作为旁注,当您必须在宽度和高度与 match_parent 匹配的 LinearLayout 内查看时,您将无法看到任何其他同级视图。
-
您是否尝试将适配器中 holder.button 的 WRAP 更改为 MATCH 布局参数?
-
@HareshChhelana 更改换行以匹配使视图的高度 = 整个屏幕的高度,因此一次只显示一个视图。 layoutParams 中设置的宽度已经设置为 Match_Parent,所以这不是问题。我想重申,我不想在适配器级别设置 layoutParams。维度已经并且应该在 XML 中定义
标签: android xml android-layout android-recyclerview