【问题标题】:SwipeRefreshLayout is filling parent in AndroidSwipeRefreshLayout 正在填充 Android 中的父级
【发布时间】:2016-03-14 13:52:01
【问题描述】:

我正在尝试使用SwipeToRefreshLayout 来更新标记内的一些信息。虽然我使用android:layout_width="wrap_content" 来保持内容大小,但由于某种原因,它总是填满父级,在信息内容下方留下巨大的空间。我做错了什么?

顺便说一句,如果我没有SwipeRefreshLayout,而只使用ScrollView,则不会出现该空白。

这是我的 XML 代码:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/svMarker"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/svMarkerInfo">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:id="@+id/llMarkerInfo">
        </LinearLayout>
    </ScrollView>

</android.support.v4.widget.SwipeRefreshLayout>

感谢您的回答!

我还留下了使用SwipeRefreshLayout 显示的图像。标记信息后面有一张地图:

如果我不使用SwipeRefreshLayout,标记信息将显示在下一个方式,这在视觉上是我正在寻找的。但我错过了 SwipeToRefresh 更新:

【问题讨论】:

  • 您还没有在线性布局中添加任何元素吗?尝试添加一些 TextView 或其他东西,以便它可以增加一些高度。
  • 我简化了它。将添加一个图像,以便您可以看到它里面有什么。但是,正如我所说,如果我拿走 SwipeRefreshLayout
  • 你不能用回收视图代替滚动视图和线性布局吗?这样您就可以设置一个相同的适配器来创建此布局。
  • 我可以使用任何必要的东西来解决问题。这就是为什么我要问:)如果你有解决方案,请发布它
  • 用户相对布局/线性布局作为父布局。在 Layout 内部用户 SwipeLayout 和其他组件,例如 textviews、buttons。在滑动布局内部使用 Recyclerview。

标签: android android-layout swiperefreshlayout


【解决方案1】:

SwipeRefreshLayout 将在使用侦听器拖动地图时禁用,并且只有在您向下滑动后半部分(即地图下方的布局)时才会进行刷新。要获得地图拖动事件,我们需要做一些解决方法,因为 Google 没有直接支持,而这个库 MapStateListener 已经做到了。只需将MapStateListener.javaTouchableMapFragment.javaTouchableWrapper.java 这三个类粘贴到您的项目中即可。

这是一个工作示例。

MainActivity.java

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback
{
    private SwipeRefreshLayout swipeRefreshLayout;
    private View  secondHalf;
    private TouchableMapFragment mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.svMarker);
        secondHalf = findViewById(R.id.secondHalf);

        setUpMap();

        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
        {
            @Override
            public void onRefresh()
            {
                // A thread to keep RefreshLayout busy for 5 seconds
                if(!swipeRefreshLayout.isRefreshing())
                    new LoadImagesTask().execute();
            }
        });
    }

    public void setUpMap()
    {
        try
        {
            if (mMap == null)
            {
                mMap = ((TouchableMapFragment) getSupportFragmentManager()
                        .findFragmentById(R.id.firstHalf));
                mMap.getMapAsync(this);

            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap)
    {
        new MapStateListener(googleMap, mMap, this)
        {
            @Override
            public void onMapTouched()
            {
                // Map touched
                swipeRefreshLayout.setEnabled(false);
            }

            @Override
            public void onMapReleased() {
                // Map released
                swipeRefreshLayout.setEnabled(true);
            }

            @Override
            public void onMapUnsettled() {
                // Map unsettled
            }

            @Override
            public void onMapSettled() {
                // Map settled
            }
        };
    }

    private class LoadImagesTask extends AsyncTask<Void, Void, Void>
    {
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... voids)
        {
            try
            {
                for (int i = 1; i <= 5; i++)
                {
                    Thread.sleep(1000);
                }
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid)
        {
            super.onPostExecute(aVoid);
            swipeRefreshLayout.setRefreshing(false);
        }
    }
}

ma​​in.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/svMarker"
                                              xmlns:android="http://schemas.android.com/apk/res/android"
                                              android:layout_width="match_parent"
                                              android:layout_height="match_parent"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:weightSum="2">

        <fragment
            android:id="@+id/firstHalf"
            android:name="com.esealed.watermeterclient.TouchableMapFragment"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            />

        <ScrollView
            android:id="@+id/secondHalf"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="@color/colorAccent">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

               <!-- Other views comes here -->

            </LinearLayout>
        </ScrollView>
    </LinearLayout>

</android.support.v4.widget.SwipeRefreshLayout>

【讨论】:

  • 谢谢。问题在于,如果我在地图上向下滚动,SwipeRefreshLayout 也会出现,如果你拿走 SwipeRefreshLayout,这违反了 Google 设计规范 (google.com/design/spec/patterns/…),这基本上就是我在我的代码中所做的:)
  • @DiieBarcia SwipeRefreshLayout 应该只在你拖动后半部分时才起作用...而不是在前半部分( MAP )并且刷新应该从顶部出现?
  • 但是“加载图标”会出现在屏幕顶部。如果用户在标记信息上滑动,会使他感到困惑,因为“加载图标”不会出现在标记信息
  • 感谢您的回答,我真的很感谢您的努力,但我找到了解决问题的方法。我不明白为什么直接使用 wrap_content 不能解决问题......现在将发布我的答案
【解决方案2】:

我能想到的唯一解决方案是动态定义 SwipeRefreshLayout 大小。无需更改我的 XML 文件。

在我管理标记信息的 MapActivity.class 上,每次显示新的标记信息时,我都会调用下一个方法:

LinearLayout llMarkerInfo = (LinearLayout) findViewById(R.id.llMarkerInfo);
SwipeRefreshLayout svMarker = (SwipeRefreshLayout) findViewById(R.id.svMarker);

//First i register to the listener so I can get the measured size of the marker information's layout
ViewTreeObserver vto = llMarkerInfo.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override        
    public void onGlobalLayout() {

        //I get the measured width and height of the marker information's layout
        int width = llMarkerInfo.getMeasuredWidth();
        int height = llMarkerInfo.getMeasuredHeight();

        //Set that size to the SwipeToRefresh layout
        LinearLayout.LayoutParams svParams = new LinearLayout.LayoutParams(width, height);
        svMarker.setLayoutParams(svParams);

        //Unregister the listener so is not called many times
        if (Build.VERSION.SDK_INT < 16)
            llMarkerInfo.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        else
            llMarkerInfo.getViewTreeObserver().removeOnGlobalLayoutListener(this);
     }
});

这样,我精确地定义了我的标记信息布局的大小,到我的SwipeRefreshLayout,动态地。

最终结果的图像(预期 = 现实):

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 2016-02-02
    相关资源
    最近更新 更多