代码之家  ›  专栏  ›  技术社区  ›  pbristow

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

  •  5
  • pbristow  · 技术社区  · 8 年前

    我的Android应用程序中有几个基本结构相同的活动,我正在尝试让我的布局变得干爽。重复的代码如下所示。它包含一个带有页脚的可滚动区域,页脚有“后退”和“仪表板”链接。还有一个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>
    

    要消除活动重复,我想我需要做的是创建一个从LinearLayout继承的自定义ViewGroup。在该代码中,从XML文件加载上述内容。我迷茫的是如何将“活动”中的儿童内容加载到正确的位置。E、 g.假设我的活动现在包含:

    <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”出现在正确的位置?我很确定如果我这样做了,我会在页面的顶部或底部出现“废话废话”,而不是在滚动视图的中间。

    我使用的是API 21/v5.0+。从技术上讲,我在用哈马林做这一切,但希望这与答案无关?

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

    Mockup

    1 回复  |  直到 8 年前
        1
  •  7
  •   pbristow    8 年前

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

    我想我需要做的是创建一个从 线性布局。

    是的,您可以扩展LinearLayout类。

    我迷茫的地方是如何让活动中的儿童内容 装载到正确的位置。

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

    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用来附加其子级)方法来处理不同类型的视图:

        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放在LinearLayer中。这是您想要的最终布局:

    <?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#视图:

    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);
            }
        }
    }