android - 在特定位置插入子项的自定义 ViewGroup

标签 android xamarin android-custom-view viewgroup android-viewgroup

我的 Android 应用程序中有几个具有相同基本结构的 Activity,我正试图让我的布局变干。重复的代码如下所示。它包含一个带有页脚的可滚动区域,该页脚具有“后退”和“仪表板”链接。还有一个 FrameLayout 用于在可滚动区域的顶部应用渐变。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="689px">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <!-- THE REAL PAGE CONTENT GOES HERE -->

            </LinearLayout>
        </ScrollView>
        <ImageView
            android:src="@drawable/GradientBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom" />
    </FrameLayout>
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="50px"
        android:background="?attr/primaryAccentColor">
        <Button
          android:layout_width="wrap_content"
          android:layout_height="26px"
          android:layout_gravity="center_vertical"
          local:MvxBind="Click GoBackCommand" />
        <Button
          android:layout_width="wrap_content"
          android:layout_height="26px"
          local:MvxBind="Click ShowDashboardHomeCommand" />
    </FrameLayout>
</LinearLayout>

要删除我的 Activity 的重复项,我认为我需要做的是创建一个继承自 LinearLayout 的自定义 ViewGroup。在该代码中,从 XML 文件加载上述内容。我迷路的地方是如何让 Activity 中的子内容加载到正确的位置。例如。假设我的 Activity 现在包含:

<com.myapp.ScrollableVerticalLayoutWithDashboard
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- THE REAL PAGE CONTENT GOES HERE -->
    <TextView android:text"blah blah blah" />

</com.myapp.ScrollableVerticalLayoutWithDashboard>

现在如何使“blah blah blah”出现在正确的位置?我很确定如果我这样做,我会在页面的顶部或底部出现“blah blah blah”,而不是在 ScrollView 的中间。

我使用的是 API 21/v5.0+。从技术上讲,我正在使用 Xamarin 完成所有这些工作,但希望这与答案无关?

编辑:结果的示例如下。页脚和渐变是自定义 ViewGroup 的一部分,但其余部分将是自定义 ViewGroup 中的内容。

Mockup

最佳答案

我不了解 Xamarin,所以这是一个原生的 android 解决方案,但应该很容易翻译。

I think what I need to do is create a custom ViewGroup inherited from a LinearLayout.

是的,您可以扩展 LinearLayout 类。

Where I am lost is how to get the child content in the Activity to load into the correct spot.

在您的自定义实现中,您需要手动处理子项。在该自定义类的构造函数中手动扩充布局:

private LinearLayout mDecor;

public ScrollableVerticalLayoutWithDashboard(Context context, AttributeSet attrs) {
      super(context, attrs);
      // inflate the layout directly, this will pass through our addView method
      LayoutInflater.from(context).inflate(R.layout.your_layout, this);
}

然后覆盖 addView()(ViewGroup 使用它来附加它的子项)方法来处理不同类型的 View :

    private LinearLayout mDecor;

    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        // R.id.decor will be an id set on the root LinearLayout in the layout so we can know
        // the type of view
        if (child.getId() != R.id.decor) {
            // this isn't the root of our inflated view so it must be the actual content, like
            // the bla bla TextView
            // R.id.content will be an id set on the LinearLayout inside the ScrollView where
            // the content will sit
            ((LinearLayout) mDecor.findViewById(R.id.content)).addView(child, params);
            return;
        }
        mDecor = (LinearLayout) child; // keep a reference to this static part of the view
        super.addView(child, index, params); // add the decor view, the actual content will
        // not be added here
    }

在 Xamarin 中,您正在寻找 https://developer.xamarin.com/api/member/Android.Views.ViewGroup.AddView/p/Android.Views.View/System.Int32/Android.Views.ViewGroup+LayoutParams/方法来覆盖。请记住,这是一个简单的实现。

编辑:与其将 LinearLayout 放入 LinearLayout 中,不如使用 'merge' 标签。这是您想要的最终布局:

<?xml version="1.0" encoding="utf-8" ?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto">
  <FrameLayout
      android:id="@+id/svfFrame1"
      android:layout_width="match_parent"
      android:layout_height="0dp"
      android:layout_weight="1">
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="689px">
      <LinearLayout
          android:id="@+id/svfContentLayout"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:orientation="vertical"
          android:paddingBottom="23px" />
    </ScrollView>
    <ImageView
        android:src="@drawable/GradientBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom" />
  </FrameLayout>
  <FrameLayout
      android:id="@+id/svfFrame2"
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:local="http://schemas.android.com/apk/res-auto"
      android:layout_width="match_parent"
      android:layout_height="50px"
      android:background="?attr/primaryAccentColor">
    <Button
      android:id="@+id/FooterBackButton"
      android:layout_width="wrap_content"
      android:layout_height="26px"
      android:layout_gravity="center_vertical"
      android:layout_marginLeft="24px" />
    <Button
      android:id="@+id/FooterDashboardButton"
      android:layout_width="wrap_content"
      android:layout_height="26px"
      android:layout_gravity="center_vertical|right"
      android:layout_marginRight="24px" />
  </FrameLayout>
</merge>

下面是基于该布局的 Xamarin 的最终工作 C# View :

public class ScrollableVerticalLayoutWithDashboard: LinearLayout
{
    public ScrollableVerticalLayoutWithDashboard(Context context, IAttributeSet attrs) : base(context, attrs)
    {
        LayoutInflater.From(context).Inflate(Resource.Layout.ScrollableVerticalFooter, this);
        base.Orientation = Orientation.Vertical;
    }

    public override void AddView(View child, int index, ViewGroup.LayoutParams @params)
    {
        // Check to see if the child is either of the two direct children from the layout
        if (child.Id == Resource.Id.svfFrame1 || child.Id == Resource.Id.svfFrame2)
        {
            // This is one of our true direct children from our own layout.  Add it "normally" using the base class.
            base.AddView(child, index, @params);
        }
        else
        {
            // This is content coming from the parent layout, not our own inflated layout.  It 
            //   must be the actual content, like the bla bla TextView.  Add it at the appropriate location.
            ((LinearLayout)this.FindViewById(Resource.Id.svfContentLayout)).AddView(child, @params);
        }
    }
}

关于android - 在特定位置插入子项的自定义 ViewGroup,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35561290/

相关文章:

xamarin - 在 xamarin 的 Pin 标签中显示全文

android - 在自定义 View 中扫描 Wifi

Android:自定义 View 'PointsView':错误 "The following classes could not be instantiated"

android:src attrs 用于自定义 View

android - 如何自定义 IconButton 的颜色

java - 如何使用 View 计算面积、周长和半径

c# - Xamarin Forms 相对布局不会堆叠

安卓 12 : Detect if user disables/enables camera and microphone

使用 Espresso IdlingResource 进行 Android 测试

android - 是否可以使用 Xamarin 以编程方式连接到 Wi-Fi 网络?