私はアプリの開発を始めました。昨日メニューを作成しましたが、onClickメソッドが機能しません! Viewを拡張し、MainMenuObjectという名前のクラスを作成しました。このクラスは、メインメニュー内のオブジェクト(ボタン、ロゴなど)用です。メニューの開始時にアニメーションを実行しているため、それらのクラスを特別に作成しました。 MainMenuObjectクラスを作成した後、Viewを拡張し、メインメニューのすべてのボタンを含む別のクラス(OpeningTimesView)を作成し、メインアクティビティのレイアウトとして機能します。
すべてが良好で、アニメーションは非常にうまくいき、リスナーをボタンに配置したかったため、onClickListenerの実装をOpeningTimesViewクラスに追加し、onClickメソッドをオーバーライドしました。次に、setOnClickListener(this)とsetClickable(true)を使用してボタンにリスナーを追加しましたが、機能しません!私はすべてを試しました!私が間違っていることを理解するのを手伝ってください。 onClickメソッドにトーストを追加しました。トーストは「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);
}
よろしくお願いします、Elad!
解決策があります!これは実際にはこの特定の問題の解決策ではなく、まったく新しいアプローチです。私はこのスレッドを知っている誰かに送信し、彼はAndroidが持っている(Wireless Designsのような)Animation SDKを使用するように言ったので、4つのクラスでメインメニューページを行う代わりに、 Activityを拡張する1つのクラスのみでそれを実行し、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);
}
}
私はちょうど同じ問題を抱えていました-カスタムビューを作成し、v.setOnClickListener(new OnClickListener() {...});
を呼び出すことでアクティビティの新しいリスナーを登録したときに、リスナーが呼び出されませんでした。
カスタムビューでは、public boolean onTouchEvent(MotionEvent event) {...}
メソッドも上書きしました。問題は、Viewクラスのメソッドsuper.onTouchEvent(event)
を呼び出さなかったことです。これで問題は解決しました。したがって、リスナーが呼び出されない理由がわからない場合は、おそらくスーパークラスのonTouchEvent
メソッドを呼び出すのを忘れています。
Androidでカスタムコントロールを作成するのは、UIフレームワークの動作に不安がある場合は注意が必要です。まだお持ちでない場合は、これらを読むことをお勧めします。
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は、View階層の最上部からタッチイベントを配信し、下に向かって動作します。従来、階層の上位レベル(アクティビティとレイアウト)を占めるクラス消費しないタッチを転送するためのロジックが含まれています。
ですから、OpeningTimesView
を変更してViewGroup
(すべてのAndroidレイアウト)のスーパークラス)または特定のレイアウト(LinearLayout
、RelativeLayout
など)を拡張し、ボタンを子として追加することをお勧めします現時点では、イベントが実際にどこに向かっているのかという問題を混乱させる可能性のある定義済みの階層(ボタンは実際にはコンテナに「含まれていない」、単にメンバーである)がないようです。
ボタンを[〜#〜] final [〜#〜]の場所に配置するのに役立つレイアウトクラスを選択してください。アニメーションフレームワークをAndroidまたはカスタム描画コード(現在のように)で使用して、その時点まで好きなようにアニメーション化することができます。ボタンの位置とボタンの現在位置drawnは必要に応じて非常に異なることが許可されており、それが現在のAnimation Frameworkの動作方法ですAndroid(3.0より前) )...それは別の問題です。また、AbsoluteLayout
を使用すると、好きな場所にオブジェクトを配置および置換できます...ただし、アプリがすべてのAndroidデバイスでどのように見えるかに注意してくださいこれで(異なる画面サイズを与えられた)。
表示情報についての2番目のポイントについて。最も簡単な方法は、おそらく必要なときにContext.getResources().getDisplayMetrics()
を使用することです。 Activity
はContext
を継承するため、このメソッドを直接呼び出すことができます。ビューには常にContext
があり、getContext()
でアクセスできます。 Context
を構造のパラメーターとして渡すことができる他のクラス(これはAndroidの一般的なパターンです。多くのオブジェクトは、主にContext
にアクセスするためにResources
を必要とします)。
すぐに開始できるスケルトンの例を次に示します。これは、最終的な場所として3つを水平方向に1回並べるだけです。
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に設定された可視性でボタンを開始し、その後、それらを最終的な休憩場所で表示できるようにします。
ただし、ここで重要なのは、タッチイベントを受信すると、対応する子に転送することになっていることを認識するのに十分なレイアウトです。これなしでカスタムビューを作成できますが、コンテナ上のすべてのタッチをインターセプトし、数学を実行して、イベントを手動で転送するサブビューを決定する必要があります。本当にレイアウトマネージャーを機能させることができない場合、これがあなたの頼みの綱です。
お役に立てば幸いです!
カスタムビューのonTouchEventでperformClick()を呼び出すだけです。
カスタムビューでこれを使用します。
@Override
public boolean onTouchEvent(final MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
return performClick();
}
return true;
}
コンストラクターで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();
}
}
私はこれを行います:
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);
}
}
onClickListener
クラスにMainMenuObjectView
を実装します。これらはクリックに応答するオブジェクトであるためです。
別の方法は、Button
の代わりにView
を拡張することです。これは、ボタンを使用しているためです
これは、クリック可能なビューに直接実装するという考え方です。 TestView
を拡張し、必要に応じてView
をオーバーライドし、クリックにも応答するonDraw
クラスがあります。あなたがその部分を持っているので、アニメーションの実装を省きました。それはClickListener
の議論には関係ありません。
Eclairエミュレーターでテストし、期待どおりに動作します(クリック後のトーストメッセージ)
ファイル: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);
}
同じ問題がありました。私の場合、カスタムビューのルート要素としてclickable
とfocusable
をtrueに設定したLinearLayoutがあり、カスタムビュータグ自体(フラグメントのレイアウトで使用)も設定されていました。 clickable
およびfocusable
になります。動作させるために私がしなければならなかった唯一のことは、XML内からすべてのclickable
およびfocusable
属性を削除することでした:)直感に反しますが、動作しました。
callOnClick()
メソッドにonTouchEvent()
を追加するだけです
public boolean onTouchEvent(MotionEvent event) {
.....YOURCODE.....
callOnClick();
return boolean;
}
私の場合、カスタムビューでRelativeLayoutを親として使用し、それを機能させる唯一の方法は、RelativeLayoutおよびカスタムビューのコンストラクタでfocusable
およびclickable
をtrue
に設定することでした。
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();
}
});