草庐IT

android - 获取 View 每个角的位置,然后在该位置添加 View

coder 2023-12-20 原文

我正在开发一个有自定义 View 的 android 项目。单击自定义 View 时,我想要在 View 的每个角放置一个 View (一个圆圈)。

目前我只是想让它在左上角工作,但它最终出现在中间。

下面是我添加 View 的点击功能。

View view = LayoutInflater.from(getContext()).inflate(R.layout.view, this, false);

        TextView textItem = view.findViewById(R.id.lblItemText);

        textItem.setText("View: " + counter);

        view.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {

                Anchor anchor1 = new Anchor(getContext());

                anchor1.setLeft(v.getLeft());
                anchor1.setTop(CustomView.this.getTop());
                CustomView.this.addView(anchor1);
            }
        });

自定义 View 托管在相对布局中。自定义 View 扩展了 RelativeLayout 和应该进入自定义 View 左上角的 anchor View 扩展了按钮。

anchor 构造函数包含以下内容:

public Anchor(Context context)
    {
        super(context);
        this.setBackgroundResource(R.drawable.anchor);
        this.setPadding(0,0,0,0);
        this.setWidth(1);
        this.setHeight(1);
}

由于某种原因, anchor 出现在中间而不是如下所示的角落

下面有点期待。

更新

几天后取得了一些进展,我确实让它工作了,除了它使用硬编码值使其处于正确的位置,这似乎不正确。我猜这只适用于我正在测试的特定设备,另一台分辨率不同的设备将定位错误。

下面是我拥有的代码,希望能够显示我正在尝试实现的目标以及我现在拥有的屏幕截图。

private void createAnchorPoints()
    {

        //Main View
        ViewGroup mainView = activity.findViewById(android.R.id.content);

        int[] viewToBeResizedLoc = new int[2];
        viewToBeResized.getLocationOnScreen(viewToBeResizedLoc);


        //Add top left anchor
        Anchor topLeftAnchor = new Anchor(context, Anchor.ResizeMode.TOP_LEFT);
        FrameLayout.LayoutParams topLeftParms = new FrameLayout.LayoutParams(150,150);
        topLeftParms.leftMargin = viewToBeResizedLoc[0] - 50;
        topLeftParms.topMargin = viewToBeResizedLoc[1] - viewToBeResized.getHeight() - 30;
        topLeftAnchor.setLayoutParams(topLeftParms);
        mainView.addView(topLeftAnchor);

        //Add top right anchor
        Anchor topRightAnchor = new Anchor(context, Anchor.ResizeMode.TOP_RIGHT);
        FrameLayout.LayoutParams topRightParms = new FrameLayout.LayoutParams(150, 150);
        topRightParms.leftMargin = topLeftParms.leftMargin + viewToBeResized.getWidth() - 40;
        topRightParms.topMargin = topLeftParms.topMargin;
        topRightAnchor.setLayoutParams(topRightParms);
        mainView.addView(topRightAnchor);

        //Add bottom left anchor
        Anchor bottomLeftAnchor = new Anchor(context, Anchor.ResizeMode.BOTTOM_LEFT);
        FrameLayout.LayoutParams bottomLeftParms = new FrameLayout.LayoutParams(150, 150);
        bottomLeftParms.leftMargin = topLeftParms.leftMargin;
        bottomLeftParms.topMargin = topLeftParms.topMargin + viewToBeResized.getHeight() - 40;
        bottomLeftAnchor.setLayoutParams(bottomLeftParms);
        mainView.addView(bottomLeftAnchor);

        //Add bottom right anchor
        Anchor bottomRightAnchor = new Anchor(context, Anchor.ResizeMode.BOTTOM_RIGHT);
        FrameLayout.LayoutParams bottomRightParms = new FrameLayout.LayoutParams(150, 150);
        bottomRightParms.leftMargin = topRightParms.leftMargin;
        bottomRightParms.topMargin = bottomLeftParms.topMargin;
        bottomRightAnchor.setLayoutParams(bottomRightParms);
        mainView.addView(bottomRightAnchor);

    }

最佳答案

由于顶级布局是 RelativeLayout,您需要使用 RelativeLayout 可用的 View 定位来实现您想要的效果。 (参见 documentation 。)

这是您希望在 XML 中实现的目标的模型。这个模型将展示我们如何接近实际的解决方案。我正在使用标准 View ,但这无关紧要。该技术将应用于您的自定义 View 。图片来自 Android Studio 的设计器,因此没有使用代码来创建图片。

activity_main.xml

<RelativeLayout 
    android:id="@+id/relativeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:id="@+id/customView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_centerInParent="true"
        android:background="@android:color/holo_green_light" />

    <ImageView
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignStart="@id/customView"
        android:layout_alignTop="@id/customView"
        android:src="@drawable/circle"
        android:translationX="-10dp"
        android:translationY="-10dp" />

    <ImageView
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignEnd="@id/customView"
        android:layout_alignTop="@id/customView"
        android:src="@drawable/circle"
        android:translationX="10dp"
        android:translationY="-10dp" />

    <ImageView
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignBottom="@id/customView"
        android:layout_alignStart="@id/customView"
        android:src="@drawable/circle"
        android:translationX="-10dp"
        android:translationY="10dp" />

    <ImageView
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignBottom="@id/customView"
        android:layout_alignEnd="@id/customView"
        android:src="@drawable/circle"
        android:translationX="10dp"
        android:translationY="10dp" />

</RelativeLayout>

circle.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <!-- fill color -->
    <solid android:color="@android:color/holo_red_light" />
    <size
        android:width="20dp"
        android:height="20dp" />
</shape>

实际解决方案

既然我们已经证明了模型方法的有效性,我们现在必须在代码中重现该效果。我们将不得不添加圆 View 并使用 RelativeLayout View 定位和转换将其定位在父级 RelativeLayout 中。以下代码仅显示左上角的圆圈定位,但其他圆圈将以类似的方式定位。

activity_main.java

public class MainActivity extends AppCompatActivity {

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

        Drawable circle = ContextCompat.getDrawable(this, R.drawable.circle);
        ImageView imageView = new ImageView(this);
        imageView.setImageDrawable(circle);
        int circleSize = dpToPx(CIRCLE_SIZE_DP);
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(circleSize, circleSize);

        // Position top left circle within the custom view.
        lp.addRule(RelativeLayout.ALIGN_START, R.id.customView);
        lp.addRule(RelativeLayout.ALIGN_TOP, R.id.customView);

        // Uncomment these 2 lines to position the top left circle with translation.
        imageView.setTranslationX(-circleSize / 2);
        imageView.setTranslationY(-circleSize / 2);

        // Uncomment these 3 lines to position the top left circle with margins.
//        View customView = findViewById(R.id.customView);
//        lp.leftMargin = customView.getLeft() - circleSize / 2;
//        lp.topMargin = customView.getTop() - circleSize / 2;

        ((RelativeLayout) findViewById(R.id.relativeLayout)).addView(imageView, lp);
    }

    private int dpToPx(int dp) {
        return (int) (dp * getResources().getDisplayMetrics().density);
    }

    private static final int CIRCLE_SIZE_DP = 20;
}

上面的代码使用了一个缩短的布局:

activity_main.xml

<RelativeLayout 
    android:id="@+id/relativeLayout"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:id="@+id/customView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_centerInParent="true"
        android:background="@android:color/holo_green_light" />

</RelativeLayout>

也可以使用边距产生相同的定位。使用边距的代码已被注释掉,但可以使用。 (我认为负边距也可能有效,但我读到它们不是 officially supported ,所以我尽量避免使用它们。)

关于android - 获取 View 每个角的位置,然后在该位置添加 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50994978/

有关android - 获取 View 每个角的位置,然后在该位置添加 View的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  3. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  4. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  5. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  6. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  7. ruby - 按值降序排列散列,然后按升序键入 ruby - 2

    我有这样的哈希trial_hash={"key1"=>1000,"key2"=>34,"key3"=>500,"key4"=>500,"key5"=>500,"key6"=>500}我按值降序排列:my_hash=trial_hash.sort_by{|k,v|v}.reverse我现在是这样理解的:[["key1",1000],["key4",500],["key5",500],["key6",500],["key3",500],["key2",34]]但我希望当值相同时按键的升序排序。我该怎么做?例如:上面的散列将以这种方式排序:[["key1",1000],["key3",500

  8. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  9. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  10. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

随机推荐