Android onClick 方法不适用于自定义视图

发布于 2024-11-02 02:19:39 字数 2374 浏览 0 评论 0原文

我已经开始开发一个应用程序。我昨天构建了菜单,但 onClick 方法不起作用! 我创建了一个扩展 View 的类,并将其称为 MainMenuObject - 该类适用于主菜单中的任何对象(按钮、徽标等)。我为他们创建了一个特殊的类,因为我在菜单启动时制作动画。在构建了 MainMenuObject 类之后,我构建了另一个类 (OpeningTimesView),该类扩展了 View,并且其中包含主菜单的所有按钮,并将用作主活动的布局。

一切都很好,动画进行得非常顺利,我想在按钮上放置侦听器,因此我向 OpeningTimesView 类添加了 onClickListener 的实现,并重写了 onClick 方法。然后我使用 setOnClickListener(this) 和 setClickable(true) 将侦听器添加到按钮,但它不起作用!我已经尝试了一切!请帮我弄清楚我做错了什么。我已经向 onClick 方法添加了一个 toast,该方法不依赖于任何“if”,但它两者都不会显示。

(顺便说一句,有什么方法可以将屏幕宽度和高度定义为所有类都可以访问的变量?它不能是静态的,因为您从显示对象中获取高度和宽度,但必须有另一种方法)

这是代码:

public class OpeningTimesView extends View implements OnClickListener{
    private MainMenuObjectView searchButton;
    private MainMenuObjectView supportButton;
    private MainMenuObjectView aboutButton;
    private int screenWidth;
    private int screenHeight;
    public OpeningTimesView(Context context, Display dis) {
        super(context);

        this.screenWidth = dis.getWidth();
        this.screenHeight = dis.getHeight();

        searchButton = new MainMenuObjectView(context, 200, MovingMode.RIGHT, R.drawable.search, dis);
        supportButton = new MainMenuObjectView(context, 400, MovingMode.LEFT, R.drawable.support, dis);
        aboutButton = new MainMenuObjectView(context, 600, MovingMode.RIGHT, R.drawable.about, dis);

        searchButton.setClickable(true);
        supportButton.setClickable(true);
        aboutButton.setClickable(true);

        searchButton.setOnClickListener(this);
        supportButton.setOnClickListener(this);
        aboutButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view){
        Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        if(view == searchButton){
            Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        }
        else if(view == supportButton){
            Toast.makeText(getContext(), "Support button pressed", Toast.LENGTH_SHORT).show();
        }
        else Toast.makeText(getContext(), "About button pressed", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onDraw(Canvas canvas)
    {
        // Drawing the buttons
        this.searchButton.onDraw(canvas);
        this.aboutButton.onDraw(canvas);
        this.supportButton.onDraw(canvas);
    }

预先感谢,埃拉德!

I've started working on an app. I build the menu yesterday but the onClick method doesn't work!
I created a class that extends View and called her MainMenuObject - that class is for any object in the main menu (buttons, logos etc). I've created a special class for them because I'm doing an animation when the menu starts. After I've built the MainMenuObject class I've built another class (OpeningTimesView) that extends View and will have all the buttons of the main menu in it, and will function as the main activity's layout.

Everything was good, the animation went very well and I wanted to put listeners on my buttons, so I've added an implemention of onClickListener to the OpeningTimesView class, and overrided the onClick method. Then I've added the listener to the buttons with setOnClickListener(this) and setClickable(true), but it doesn't work! I've tried everything! Please help me figure out what I'm doing wrong. I've added a toast to the onClick method that doesn't depend on any "if" but it's won't show neither.

(BTW is there any way to define the screen width and height as variable that all classes can access? it can't be static because you get the height and width from a display object but there must be another way)

this is the code:

public class OpeningTimesView extends View implements OnClickListener{
    private MainMenuObjectView searchButton;
    private MainMenuObjectView supportButton;
    private MainMenuObjectView aboutButton;
    private int screenWidth;
    private int screenHeight;
    public OpeningTimesView(Context context, Display dis) {
        super(context);

        this.screenWidth = dis.getWidth();
        this.screenHeight = dis.getHeight();

        searchButton = new MainMenuObjectView(context, 200, MovingMode.RIGHT, R.drawable.search, dis);
        supportButton = new MainMenuObjectView(context, 400, MovingMode.LEFT, R.drawable.support, dis);
        aboutButton = new MainMenuObjectView(context, 600, MovingMode.RIGHT, R.drawable.about, dis);

        searchButton.setClickable(true);
        supportButton.setClickable(true);
        aboutButton.setClickable(true);

        searchButton.setOnClickListener(this);
        supportButton.setOnClickListener(this);
        aboutButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view){
        Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        if(view == searchButton){
            Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        }
        else if(view == supportButton){
            Toast.makeText(getContext(), "Support button pressed", Toast.LENGTH_SHORT).show();
        }
        else Toast.makeText(getContext(), "About button pressed", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onDraw(Canvas canvas)
    {
        // Drawing the buttons
        this.searchButton.onDraw(canvas);
        this.aboutButton.onDraw(canvas);
        this.supportButton.onDraw(canvas);
    }

Thanks in advance, Elad!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

寻找一个思念的角度 2024-11-09 02:19:39

我刚刚遇到了同样的问题 - 我创建了一个自定义视图,当我通过调用 v.setOnClickListener(new OnClickListener() {...}); 监听器在活动中为其注册一个新的监听器时只是没有接到电话。

在我的自定义视图中,我还覆盖了 public boolean onTouchEvent(MotionEvent event) {...} 方法。问题是我没有调用View类的方法 - super.onTouchEvent(event)。这解决了问题。因此,如果您想知道为什么您的侦听器没有被调用,您可能忘记调用超类的 onTouchEvent 方法,

这是一个简单的示例:

private static class CustomView extends View implements View.OnClickListener {
    public CustomView(Context context) {
        super(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);   // this super call is important !!!
        // YOUR LOGIC HERE
        return true;
    }

    @Override
    public void onClick(View v) {
        // DO SOMETHING HERE
    }
}

I just had the same Problem - I created a custom view and when I registered a new Listener for it in the activity by calling v.setOnClickListener(new OnClickListener() {...}); the listener just did not get called.

In my custom view I also overwrote the public boolean onTouchEvent(MotionEvent event) {...} method. The problem was that I did not call the method of the View class - super.onTouchEvent(event). That solved the problem. So if you are wondering why your listener does not get called you have probably forgotten to call the superclass'es onTouchEvent method

Here is a simple example:

private static class CustomView extends View implements View.OnClickListener {
    public CustomView(Context context) {
        super(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);   // this super call is important !!!
        // YOUR LOGIC HERE
        return true;
    }

    @Override
    public void onClick(View v) {
        // DO SOMETHING HERE
    }
}
灼痛 2024-11-09 02:19:39

如果您不熟悉 UI 框架的操作方式,那么在 Android 中创建自定义控件可能会很棘手。如果您还没有阅读过,我建议您阅读以下内容:

http:// developer.android.com/guide/topics/ui/declaring-layout.html

http://developer.android.com/guide/topics/ui/custom-components.html

http://developer.android.com/guide/topics/ui/layout-objects.html

请注意,当在 XML 中声明布局时,元素是嵌套的。这将创建一个布局层次结构,当仅使用 Java 代码自定义组件时,您必须自行创建该布局层次结构。

您很可能陷入了 Android 的触摸层次结构中。与其他一些流行的移动平台不同,Android 从视图层次结构的顶部开始传递触摸事件,然后向下传递。传统上占据层次结构较高级别的类(活动和布局)具有转发它们本身不消耗的触摸的逻辑。

因此,我建议您更改 OpeningTimesView 以扩展 ViewGroup (所有 Android 布局的超类)或特定布局(LinearLayoutRelativeLayout 等)并将按钮添加为子按钮。目前,似乎没有定义的层次结构(按钮并未真正“包含”在容器中,它们只是成员),这可能会混淆事件真正发生的位置的问题。

  1. 触摸应该更自然地流向按钮,从而允许触发您的单击事件。
  2. 您可以利用 Android 的布局机制来绘制视图,而不是依赖绘制代码来完成所有这些工作。

首先选择一个布局类,它将帮助您将按钮放置在其最终位置。您可以使用 Android 中的动画框架或自定义绘图代码(就像您现在拥有的那样)来按照您喜欢的方式为它们设置动画。如有必要,按钮的位置和当前绘制该按钮的位置可以有很大不同,这就是当前动画框架在 Android 中的工作方式(3.0 之前)...但这是一个单独的问题。您还可以使用 AbsoluteLayout,它允许您在任何您喜欢的位置放置和替换对象...但请注意您的应用程序在使用此设备的所有 Android 设备上的外观(考虑到不同的屏幕尺寸)。

关于显示信息的第二点。
最简单的方法可能就是在需要的地方使用 Context.getResources().getDisplayMetrics() 。 Activity继承自Context,因此可以直接调用此方法。视图始终有一个可以通过 getContext() 访问的Context。任何其他类,您都可以在构造中将 Context 作为参数传递(这是 Android 中的常见模式,您会看到许多对象需要 Context,主要是为了访问资源)。

这是一个快速启动的框架示例。这只是将三个水平排列一次作为最终位置:

Public class OpeningTimesView extends LinearLayout implements OnClickListener {
    private MainMenuObjectView searchButton;
    private MainMenuObjectView supportButton;
    private MainMenuObjectView aboutButton;
    private int screenWidth;
    private int screenHeight;

    public OpeningTimesView(Context context) {
        this(context, null);
    }

    //Thus constructor gets used if you ever instantiate your component from XML
    public OpeningTimesView(Context context, AttributeSet attrs) {
        super(context, attrs);

        /* This is a better way to obtain your screen info
        DisplayMetrics display = context.getResources().getDisplayMetrics();
        screenWidth = display.widthPixels;
        screenHeight = display.heightPixels;
        */
        //This way works also, without needing to customize the constructor
        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Display dis = wm.getDefaultDisplay();
        screenWidth = dis.getWidth();
        screenHeight = dis.getHeight();

        searchButton = new MainMenuObjectView(context, 200, MovingMode.RIGHT, R.drawable.search, dis);
        supportButton = new MainMenuObjectView(context, 400, MovingMode.LEFT, R.drawable.support, dis);
        aboutButton = new MainMenuObjectView(context, 600, MovingMode.RIGHT, R.drawable.about, dis);

        //Even if they don't extend button, if MainMenuObjectView is always clickable
        // this should probably be brought into that class's constructor
        searchButton.setClickable(true);
        supportButton.setClickable(true);
        aboutButton.setClickable(true);

        searchButton.setOnClickListener(this);
        supportButton.setOnClickListener(this);
        aboutButton.setOnClickListener(this);

        //Add the buttons to the layout (the buttons are now children of the container)
        setOrientation(LinearLayout.HORIZONTAL);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        addView(searchButton, params);
        addView(supportButton, params);
        addView(aboutButton, params);       
    }

    @Override
    public void onClick(View view){
        Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        if(view == searchButton){
            Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        }
        else if(view == supportButton){
            Toast.makeText(getContext(), "Support button pressed", Toast.LENGTH_SHORT).show();
        }
        else Toast.makeText(getContext(), "About button pressed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDraw(Canvas canvas)
    {
        //Drawing the buttons
        // This may only be necessary until they are in place, then just call super.onDraw(canvas)
        this.searchButton.onDraw(canvas);
        this.aboutButton.onDraw(canvas);
        this.supportButton.onDraw(canvas);
    }    
}

您可以从那里自定义它。也许启动按钮时将可见性设置为 View.INVISIBLE,直到您使用绘图代码或自定义动画对象对它们进行动画处理,然后使它们在最终静止位置可见。

不过,这里的关键是布局足够智能,知道当它收到触摸事件时,应该将其转发给相应的子级。您可以在没有此操作的情况下创建自定义视图,但您必须拦截容器上的所有触摸并进行数学计算以确定将事件手动转发到哪个子视图。如果您确实无法使任何布局管理器工作,那么这就是您的资源。

希望有帮助!

Creating custom controls in Android can be tricky if you aren't comfortable with how the UI Framework operates. If you haven't already, I would recommend reading these:

http://developer.android.com/guide/topics/ui/declaring-layout.html

http://developer.android.com/guide/topics/ui/custom-components.html

http://developer.android.com/guide/topics/ui/layout-objects.html

Notice that when layouts are declared in XML the elements are nested. This creates a layout hierarchy that you must create your self when customizing a component using only Java code.

Most likely you are getting caught up in Android's touch hierarchy. Unlike some other popular mobile platforms, Android delivers touch events starting at the top of the View hierarchy and works its way down. The classes that traditionally occupy the higher levels of the hierarchy (Activity and Layouts) have logic in them to forward touches they don't themselves consume.

So, what I would recommend doing is changing your OpeningTimesView to extend a ViewGroup (the superclass of all Android layouts) or a specific layout (LinearLayout, RelativeLayout, etc.) and add your buttons as children. Right now, there does not seem to be a defined hierarchy (the buttons aren't really "contained" in the container, they're just members) which may be confusing the issue as to where events are really going.

  1. The touches should more naturally flow down to the buttons, allowing your click events to trigger
  2. You can take advantage of Android's layout mechanisms to draw your view instead of relying on drawing code to do all of that.

Pick a layout class to start with that will help you place your buttons in their FINAL locations. You can use the animation framework in Android or custom drawing code (like you have now) to animate them anyway you like up to that point. The location of a button and where that button is currently drawn are allowed to be very different if necessary, and that's how the current Animation Framework works in Android (prior to 3.0)...but that's a separate issue. You also have AbsoluteLayout, which allows you to place and replace objects anywhere you like...but be careful of how your app looks on all Android devices with this one (given the different screen sizes).

As to your second point about display info.
The simplest method is probably just to use Context.getResources().getDisplayMetrics() wherever you need it. Activity inherits from Context, so they can call this method directly. Views always have a Context you can access with getContext(). Any other classes you can just pass the Context as a parameter in construction (this is a common pattern in Android, you'll see many objects require a Context, mainly to access Resources).

Here's a skeleton example to jump start things. This just lines the three up horizontally once as a final location:

Public class OpeningTimesView extends LinearLayout implements OnClickListener {
    private MainMenuObjectView searchButton;
    private MainMenuObjectView supportButton;
    private MainMenuObjectView aboutButton;
    private int screenWidth;
    private int screenHeight;

    public OpeningTimesView(Context context) {
        this(context, null);
    }

    //Thus constructor gets used if you ever instantiate your component from XML
    public OpeningTimesView(Context context, AttributeSet attrs) {
        super(context, attrs);

        /* This is a better way to obtain your screen info
        DisplayMetrics display = context.getResources().getDisplayMetrics();
        screenWidth = display.widthPixels;
        screenHeight = display.heightPixels;
        */
        //This way works also, without needing to customize the constructor
        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Display dis = wm.getDefaultDisplay();
        screenWidth = dis.getWidth();
        screenHeight = dis.getHeight();

        searchButton = new MainMenuObjectView(context, 200, MovingMode.RIGHT, R.drawable.search, dis);
        supportButton = new MainMenuObjectView(context, 400, MovingMode.LEFT, R.drawable.support, dis);
        aboutButton = new MainMenuObjectView(context, 600, MovingMode.RIGHT, R.drawable.about, dis);

        //Even if they don't extend button, if MainMenuObjectView is always clickable
        // this should probably be brought into that class's constructor
        searchButton.setClickable(true);
        supportButton.setClickable(true);
        aboutButton.setClickable(true);

        searchButton.setOnClickListener(this);
        supportButton.setOnClickListener(this);
        aboutButton.setOnClickListener(this);

        //Add the buttons to the layout (the buttons are now children of the container)
        setOrientation(LinearLayout.HORIZONTAL);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        addView(searchButton, params);
        addView(supportButton, params);
        addView(aboutButton, params);       
    }

    @Override
    public void onClick(View view){
        Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        if(view == searchButton){
            Toast.makeText(getContext(), "Search button pressed", Toast.LENGTH_SHORT).show();
        }
        else if(view == supportButton){
            Toast.makeText(getContext(), "Support button pressed", Toast.LENGTH_SHORT).show();
        }
        else Toast.makeText(getContext(), "About button pressed", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDraw(Canvas canvas)
    {
        //Drawing the buttons
        // This may only be necessary until they are in place, then just call super.onDraw(canvas)
        this.searchButton.onDraw(canvas);
        this.aboutButton.onDraw(canvas);
        this.supportButton.onDraw(canvas);
    }    
}

You can customize this from there. Perhaps starting the buttons with visibility set to View.INVISIBLE until you animate them in with your drawing code or a custom Animation object, then making them visibile in their final resting place.

The key here, though, is the the layout is smart enough to know that when it receives a touch event it is supposed to forward it to the corresponding child. You can create a custom view without this, but you will have to intercept all touches on the container and do the math to determine which subview to manually forward the event to. If you truly can't make any layout manager work, this is your recourse.

Hope that Helps!

一口甜 2024-11-09 02:19:39

您只需在自定义视图的onTouchEvent 中调用performClick() 即可。

在您的自定义视图中使用它:

    @Override
    public boolean onTouchEvent(final MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_UP){
            return performClick();
        }
        return true;
    }

You can just call performClick() in onTouchEvent of your custom view.

Use this in you custom view:

    @Override
    public boolean onTouchEvent(final MotionEvent event) {
        if(event.getAction() == MotionEvent.ACTION_UP){
            return performClick();
        }
        return true;
    }
2024-11-09 02:19:39

我这样做:

public class YourView extends LinearLayout implements OnClickListener {
    OnClickListener listener;

    //... constructors

    public void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }

    @Override
    public void onClick(View v) {
        if (listener != null)
             listener.onClick(v);
    }
}

I do this so:

public class YourView extends LinearLayout implements OnClickListener {
    OnClickListener listener;

    //... constructors

    public void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }

    @Override
    public void onClick(View v) {
        if (listener != null)
             listener.onClick(v);
    }
}
偏闹i 2024-11-09 02:19:39

您必须在构造函数中调用 setOnClickListener(this) 并在自身上实现 View.OnClickListener

这样:

public class MyView extends View implements View.OnClickListener {

    public MyView(Context context) {
        super(context);
        setOnClickListener(this);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(getContext(), "On click.", Toast.LENGTH_SHORT).show();
    }
}

You have to call setOnClickListener(this) in contructor(s) and implement View.OnClickListener on self.

In this way:

public class MyView extends View implements View.OnClickListener {

    public MyView(Context context) {
        super(context);
        setOnClickListener(this);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Toast.makeText(getContext(), "On click.", Toast.LENGTH_SHORT).show();
    }
}
慢慢从新开始 2024-11-09 02:19:39

我也有同样的问题。就我而言,我将 LinearLayout 作为自定义视图的根元素,将 clickablefocusable 设置为 true,并将自定义视图标记本身(在片段的布局中使用) )也被设置为可点击可聚焦。事实证明,要让它工作,我唯一要做的就是从 XML 中删除所有 clickablefocusable 属性:) 违反直觉,但它有效。

I had the same problem. In my case I had a LinearLayout as a root element of my custom view, with clickable and focusable set to true, and the custom view tag itself (used in a fragment's layout) was also set to be clickable and focusable. Turns out that the only thing I had to do to get it working was to remove all the clickable and focusable attributes from within the XML :) Counter-intuitive, but it worked.

孤千羽 2024-11-09 02:19:39

MainMenuObjectView 类中实现 onClickListener,因为这些对象将响应点击。
另一种选择是扩展 Button 而不是 View,因为您只使用其中的按钮


更新:完整示例


这是将其直接实现到可点击视图中的想法。有一个 TestView 类,它可以根据需要扩展 View 并重写 onDraw,并且还可以响应点击。我遗漏了任何动画实现,因为您有该部分,并且它与 ClickListener 讨论无关。
我在 Eclair 模拟器中对其进行了测试,它按预期工作(单击后出现 Toast 消息)。

文件:Test.java

package com.aleadam.test;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

public class Test extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
        TextView label = new TextView(this);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
             LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        label.setText("Click the circle!");
        TestView testView = new TestView(this);
        ll.addView(label, layoutParams);
        ll.addView(testView, layoutParams);
        setContentView(ll);
    }
}

文件:TestView.java

package com.aleadam.test;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class TestView extends View implements OnClickListener {
    Context context;

    public TestView(Context context) {
        super(context);
        this.context = context;
        setOnClickListener(this);
    }

    public void onClick(View arg0) {
        Toast.makeText(context, "View clicked.", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDraw (Canvas canvas) {
        super.onDraw(canvas);
        this.setBackgroundColor(Color.LTGRAY);
        Paint paint = new Paint (Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.RED);
        canvas.drawCircle(20, 20, 20, paint);
    }
}

和一些不可点击的,你可以添加一个带有
布尔参数来确定 ClickListener 是否附加到视图:

public TestView(Context context, boolean clickable) {
    super(context);
    this.context = context;
    if (clickable)
        setOnClickListener(this);
}

Implement the onClickListener in the MainMenuObjectView class, since those are the objects that will respond to clicks.
Another alternative would be to extend Button instead of View, because you are using only buttons in there


Update: Full example


This is the idea to implement it directly into the clickable views. There is a TestView class that extends View and overrides onDraw, as you need it to, and also responds to clicks. I left out any animation implementation as you have that part and it's not relevant to the ClickListener discussion.
I tested it in an Eclair emulator and it works as expected (a Toast message after a click).

file: Test.java

package com.aleadam.test;

import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;

public class Test extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
        TextView label = new TextView(this);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
             LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        label.setText("Click the circle!");
        TestView testView = new TestView(this);
        ll.addView(label, layoutParams);
        ll.addView(testView, layoutParams);
        setContentView(ll);
    }
}

file: TestView.java

package com.aleadam.test;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class TestView extends View implements OnClickListener {
    Context context;

    public TestView(Context context) {
        super(context);
        this.context = context;
        setOnClickListener(this);
    }

    public void onClick(View arg0) {
        Toast.makeText(context, "View clicked.", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDraw (Canvas canvas) {
        super.onDraw(canvas);
        this.setBackgroundColor(Color.LTGRAY);
        Paint paint = new Paint (Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.RED);
        canvas.drawCircle(20, 20, 20, paint);
    }
}

If you need some clickable and some not clickable, you can add a constructor with a
boolean argument to determine whether the ClickListener is attached or not to the View:

public TestView(Context context, boolean clickable) {
    super(context);
    this.context = context;
    if (clickable)
        setOnClickListener(this);
}
源来凯始玺欢你 2024-11-09 02:19:39

我有办法解决!
这并不是这个特定问题的真正解决方案,而是一种全新的方法。
我将此线程发送给我认识的人,他告诉我使用 android 具有的动画 SDK(如提到的无线设计),因此我没有使用 4 个类来执行主菜单页面,而是只使用一个扩展类来执行此操作Activity 和 Animation 类提供了许多动画选项。
我要感谢你们对我的帮助,你们很棒。
如果有人遇到此线程有相同的问题或其他问题,我将添加代码:

package elad.openapp;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.Toast;

public class OpeningTimes extends Activity implements OnClickListener{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    // Disabling the title bar..
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.main);

    // Create the buttons and title objects
    ImageView title = (ImageView)findViewById(R.id.title_main);
    ImageView search = (ImageView)findViewById(R.id.search_button_main);
    ImageView support = (ImageView)findViewById(R.id.support_button_main);
    ImageView about = (ImageView)findViewById(R.id.about_button_main);

    // Setting the onClick listeners
    search.setOnClickListener(this);
    support.setOnClickListener(this);
    about.setOnClickListener(this);

    setButtonsAnimation(title, search, support, about);

}

@Override
public void onClick(View v) {
    if(v.getId()==R.id.search_button_main){
        v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        startActivity(new Intent(this,SearchPage.class));
    }
    else if(v.getId()==R.id.support_button_main){
        v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        Toast.makeText(this, "Coming soon...", Toast.LENGTH_LONG).show();
    }
    else if(v.getId()==R.id.about_button_main){

        v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        Toast.makeText(this, "Coming soon...", Toast.LENGTH_LONG).show();
    }
}

// Setting the animation on the buttons
public void setButtonsAnimation(ImageView title, ImageView search, ImageView support, ImageView about){
    // Title animation (two animations - scale and translate)
    AnimationSet animSet = new AnimationSet(true);

    Animation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f);
    anim.setDuration(750);
    animSet.addAnimation(anim);

    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);
    animSet.addAnimation(anim);

    title.startAnimation(animSet);

    // Search button animation
    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1.5f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);

    search.startAnimation(anim);

    // Support button animation
    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1.5f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);

    support.startAnimation(anim);

    // About button animation
    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, 3f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);

    about.startAnimation(anim);
}
}

I've got a solution!
It's not really a solution for this specific issue, but a whole new approach.
I sent this thread to somebody I know and he told me to use the Animation SDK the android has (like Wireless Designs mentioned), so instead of doing the main menu page with 4 classes, I'm doing it only with one class that extends Activity, and the Animation class offers many animation options.
I want to thank you both for helping me, you are great.
I'm adding the code if someone will encounter this thread with the same problem or something:

package elad.openapp;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.HapticFeedbackConstants;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.Toast;

public class OpeningTimes extends Activity implements OnClickListener{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    // Disabling the title bar..
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.main);

    // Create the buttons and title objects
    ImageView title = (ImageView)findViewById(R.id.title_main);
    ImageView search = (ImageView)findViewById(R.id.search_button_main);
    ImageView support = (ImageView)findViewById(R.id.support_button_main);
    ImageView about = (ImageView)findViewById(R.id.about_button_main);

    // Setting the onClick listeners
    search.setOnClickListener(this);
    support.setOnClickListener(this);
    about.setOnClickListener(this);

    setButtonsAnimation(title, search, support, about);

}

@Override
public void onClick(View v) {
    if(v.getId()==R.id.search_button_main){
        v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        startActivity(new Intent(this,SearchPage.class));
    }
    else if(v.getId()==R.id.support_button_main){
        v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        Toast.makeText(this, "Coming soon...", Toast.LENGTH_LONG).show();
    }
    else if(v.getId()==R.id.about_button_main){

        v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
        Toast.makeText(this, "Coming soon...", Toast.LENGTH_LONG).show();
    }
}

// Setting the animation on the buttons
public void setButtonsAnimation(ImageView title, ImageView search, ImageView support, ImageView about){
    // Title animation (two animations - scale and translate)
    AnimationSet animSet = new AnimationSet(true);

    Animation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f);
    anim.setDuration(750);
    animSet.addAnimation(anim);

    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);
    animSet.addAnimation(anim);

    title.startAnimation(animSet);

    // Search button animation
    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1.5f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);

    search.startAnimation(anim);

    // Support button animation
    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1.5f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);

    support.startAnimation(anim);

    // About button animation
    anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
            Animation.RELATIVE_TO_SELF, 3f, Animation.RELATIVE_TO_SELF, 0.0f);
    anim.setDuration(750);

    about.startAnimation(anim);
}
}
不爱素颜 2024-11-09 02:19:39

就我而言,我的自定义视图中有一个RelativeLayout作为父级,使其工作的唯一方法是将focusableclickable设置为true 在RelativeLayout和自定义视图的构造函数中,膨胀布局后,添加以下内容:

View view = inflate(getContext(), R.layout.layout_my_custom_view, this);

view.findViewById(R.id.theparent).setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            performClick();
        }
    });

In my case I had a RelativeLayout as a parent in my custom view and the only way to make it work was to set focusable and clickable to true in the RelativeLayout and in the constructor of the custom view, after inflating the layout, add this:

View view = inflate(getContext(), R.layout.layout_my_custom_view, this);

view.findViewById(R.id.theparent).setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            performClick();
        }
    });
谁的年少不轻狂 2024-11-09 02:19:39

就这么简单:

public class FancyButton
 extends FrameLayout
 implements View.OnClickListener { ..

    void yourSetupFunction(Context context, @Nullable AttributeSet attrs) {
        ..
        super.setOnClickListener(this); // NOTE THE SUPER
    }

    OnClickListener consumerListener = null;
    @Override
    public void setOnClickListener(@Nullable OnClickListener l) {
        consumerListener = l;
        // DO NOT CALL SUPER HERE
    }

    @Override
    public void onClick(View v) {
        Log.i("dev","perform my custom functions, and then ...");
        if (consumerListener != null) { consumerListener.onClick(v); }
    }
  1. 实现 View.OnClickListener,因此在 setOnClickListener 中有一个
  2. onClick(View v)
  3. ,“记住”从外界设置的侦听器
  4. 将实际侦听器设置为我们(使用“super”。.. .)
  5. 在onClick中做你自定义的东西,然后调用外界的onClick

It is this easy:

public class FancyButton
 extends FrameLayout
 implements View.OnClickListener { ..

    void yourSetupFunction(Context context, @Nullable AttributeSet attrs) {
        ..
        super.setOnClickListener(this); // NOTE THE SUPER
    }

    OnClickListener consumerListener = null;
    @Override
    public void setOnClickListener(@Nullable OnClickListener l) {
        consumerListener = l;
        // DO NOT CALL SUPER HERE
    }

    @Override
    public void onClick(View v) {
        Log.i("dev","perform my custom functions, and then ...");
        if (consumerListener != null) { consumerListener.onClick(v); }
    }
  1. implement View.OnClickListener, and hence have an
  2. onClick(View v)
  3. in setOnClickListener, "remember" the listener set from the outside world
  4. set the actual listener to be us (using "super." ...)
  5. in onClick do you custom stuff, and then call the outside world's onClick
韵柒 2024-11-09 02:19:39

只需将 callOnClick() 添加到您的 onTouchEvent() 方法中

public boolean onTouchEvent(MotionEvent event) {
        .....YOURCODE.....
        callOnClick();
        return boolean;
    }

just add callOnClick() to your onTouchEvent() method

public boolean onTouchEvent(MotionEvent event) {
        .....YOURCODE.....
        callOnClick();
        return boolean;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文