这是我的更正后的代码,仍然无法正常工作,这次我还包括了logcat以帮助识别我的错误。再次感谢您对我最后一个要求的惊人回应;
package com.example.michaelheneghan.example1;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.graphics.Color;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.Button;
import android.widget.TextView;
import android.view.MotionEvent;
import android.view.GestureDetector;
import android.support.v4.view.GestureDetectorCompat;
import android.widget.EditText;
import org.w3c.dom.Text;
public class MainActivity extends ActionBarActivity implements GestureDetector.OnGestureListener,
GestureDetector.OnDoubleTapListener{
//change back to TextView
private Button mikesButton;
private TextView mikesText;
private GestureDetectorCompat gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
////////// Layout object is added //////////////////
RelativeLayout myLayout = new RelativeLayout(this);
////////// Button object being created /////////////////
this.mikesButton = (Button) findViewById(R.id.mikesButton);
this.mikesButton.setText("Click Me");
this.mikesButton.setBackgroundColor(Color.RED);
this.mikesText = (TextView)findViewById(R.id.mikesText);
///////// Set up an event listener for the button //////////////
this.mikesButton.setOnClickListener( /// listen for an event on this button
new Button.OnClickListener() { //// Interface
public void onClick(View v) { //// Callback method
TextView Change = (TextView) findViewById(R.id.mikesButton);
Change.setText("Good job, it changed!");
}
}
);
///////////// Listening for multiple events ////////////////////
mikesButton.setOnLongClickListener(
new Button.OnLongClickListener(){ //// Interface
public boolean onLongClick(View v) { //// Callback method
TextView Change = (TextView) findViewById(R.id.mikesText);
Change.setText("Good job, it changed when you held onto the button!");
return true;
}
}
);
//////////// Set up an event listener for a double tap event //////////////
mikesButton = (Button) findViewById(R.id.mikesButton); /////// Reference to the button
this.gestureDetector = new GestureDetectorCompat(this,this); /// an object from GD class to detect gestures
gestureDetector.setOnDoubleTapListener(this); /// Set method to detect double taps
///////// Input object called mikesText is added //////////////////////
//mikesText.setId(2);
RelativeLayout.LayoutParams textdeets = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
);
///////// Give rules to position widgets ////////////////////////
textdeets.addRule(RelativeLayout.ABOVE, mikesButton.getId()); /// Place above the button that is already centered//
textdeets.addRule(RelativeLayout.CENTER_HORIZONTAL); //// place in the middle of the screen ////
textdeets.setMargins(0, 0, 0, 50); ///// where to place; left, top, right, bottom ///////
////////////// Rules of where to place the layout object ///////////////
RelativeLayout.LayoutParams buttonDeets = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
);
//////////// Rules of where to place the button object ////////////////
buttonDeets.addRule(RelativeLayout.CENTER_HORIZONTAL);
buttonDeets.addRule(RelativeLayout.CENTER_VERTICAL);
////////// Add widgets to layout and their rules///////////
myLayout.addView(mikesButton, buttonDeets); //Second param shows android the rules of how it is layed out
myLayout.addView(mikesText, textdeets);
}
////////////// implement gesture methods from GestureDetector class ///////////////////////
@Override
public boolean onDoubleTap(MotionEvent e) {
mikesButton.setText("onDoubleTap"); /// set message to change text on screen to whatever gesture just occured
return true; // return true on all gesture methods so the system shows the event was handled
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
mikesButton.setText("onSingleTapConfirmed"); /// set message to change text on screen to whatever gesture just occured
return true;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
mikesButton.setText("onDoubleTapEvent");
return true;
}
@Override
public boolean onDown(MotionEvent e) {
mikesButton.setText("onDown");
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
mikesButton.setText("onSingleTapUp");
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
mikesButton.setText("onScroll");
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
mikesButton.setText("onFling");
return true;
}
////////// Override default method so that system checks if the event is a gesture before checking for common event /////////////
@Override
public boolean onTouchEvent(MotionEvent event) {
this.gestureDetector.onTouchEvent(event); /// add the gesture detector variable to check for
return super.onTouchEvent(event);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
主要xml是:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/stringMessage"
android:id="@+id/mikesText"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/buttonName"
android:id="@+id/mikesButton"
android:layout_centerVertical="true"
android:layout_alignRight="@+id/mikesText"
android:layout_alignEnd="@+id/mikesText" />
我得到的日志是
10-09 11:16:47.471 5464-5464/com.example.michaelheneghan.example1 I/art﹕ Not late-enabling -Xcheck:jni (already on)
10-09 11:16:47.471 5464-5464/com.example.michaelheneghan.example1 I/art﹕ Late-enabling JIT
10-09 11:16:47.473 5464-5464/com.example.michaelheneghan.example1 I/art﹕ JIT created with code_cache_capacity=2MB compile_threshold=1000
10-09 11:16:47.497 5464-5464/com.example.michaelheneghan.example1 W/System﹕ ClassLoader referenced unknown path: /data/app/com.example.michaelheneghan.example1-2/lib/x86
10-09 11:16:47.599 5464-5464/com.example.michaelheneghan.example1 D/AndroidRuntime﹕ Shutting down VM
10-09 11:16:47.599 5464-5464/com.example.michaelheneghan.example1 E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.michaelheneghan.example1, PID: 5464
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.michaelheneghan.example1/com.example.michaelheneghan.example1.MainActivity}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:4309)
at android.view.ViewGroup.addView(ViewGroup.java:4145)
at android.view.ViewGroup.addView(ViewGroup.java:4117)
at com.example.michaelheneghan.example1.MainActivity.onCreate(MainActivity.java:105)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
最佳答案
我看到的第一件事是,您为按钮和textview(R.id.mikesButton)使用了相同的资源ID:
mikesButton = (Button) findViewById(R.id.mikesButton); /// ref to the location by id
public boolean onLongClick(View v) { //// Callback method
TextView Change = (TextView) findViewById(R.id.mikesButton);
Change.setText("Good job, it changed when you held onto the button!");
return true;
}
在某个时候应该给您强制转换例外。 @ geert-berkers这样的LogCat会很有帮助。
编辑
这是毫无价值的:
Button mikesButton = new Button(this);
mikesButton.setText("Click Me");
mikesButton.setBackgroundColor(Color.RED);
//mikesButton.setId(1);
由于它从未添加到布局中,因此,从xml布局activity_main扩展了臀部之后,您只是一行而已:
mikesButton = (Button) findViewById(R.id.mikesButton); /// ref to the location
按ID恢复它应该是:
Button mikesButton = (Button) findViewById(R.id.mikesButton);
mikesButton.setText("Click Me");
mikesButton.setBackgroundColor(Color.RED);
//mikesButton.setId(1); <-- never do this when inflating from xml R.id.mikesButton is already the id
另一个错误是您从未设置过mikesButton,mikesText属性,这就是为什么:
protected void onCreate(Bundle savedInstanceState) {
...
Button mikesButton = new Button(this); //<-- this means you are using a local to the method an not the class property you define
...
}
它应该是 :
protected void onCreate(Bundle savedInstanceState) {
...
this.mikesButton = (Button) findViewById(R.id.mikesButton);
this.mikesText = (TextView) findViewById(R.id.mikesText); <-- Notice that i chaged the id so it should be changed on the activity_main layout
...
}
您已经使用设置了布局:
setContentView(R.layout.activity_main);
所以稍后再做:
/////// Sets this activities content to this view & change background color //////////
setContentView(myLayout);
将从您从xml加载的布局替换为您动态创建的布局,因此从xml加载的所有视图都不再位于活动布局中。
恢复所有更改:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
////////// Button object being created /////////////////
this.mikesButton = (Button) findViewById(R.id.mikesButton); /// ref to the location by id
this.mikesButton.setText("Click Me");
this.mikesButton.setBackgroundColor(Color.RED);
///////// Input object called mikesText is added //////////////////////
this.mikesText = (TextView) findViewById(R.id.mikesText);
///////// Set up an event listener for the button //////////////
this.mikesButton.setOnClickListener( /// listen for an event on this button
new Button.OnClickListener() { //// Interface
public void onClick(View v) { //// Callback method
MainActivity.this.mikesText.setText("Good job, it changed!");
}
}
);
///////////// Listening for multiple events ////////////////////
this.mikesButton.setOnLongClickListener(
new Button.OnLongClickListener() { //// Interface
public boolean onLongClick(View v) { //// Callback method
MainActivity.this.mikesText.setText("Good job, it changed when you held onto the button!");
return true;
}
}
);
//////////// Set up an event listener for a double tap event //////////////
this.gestureDetector = new GestureDetectorCompat(this, this); /// an object from GD class to detect gestures
this.gestureDetector.setOnDoubleTapListener(this); /// Set method to detect double taps
//TODO: if you want to add a button from code
Button otherButton = new Button(this);
otherButton.setText("Hey i was made by code");
otherButton.setBackgroundColor(Color.BLUE);
////////////// Rules of where to place the layout object ///////////////
RelativeLayout.LayoutParams buttonDeets = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT
);
//////////// Rules of where to place the button object ////////////////
buttonDeets.addRule(RelativeLayout.CENTER_HORIZONTAL);
buttonDeets.addRule(RelativeLayout.CENTER_VERTICAL);
RelativeLayout mainLayout = this.findViewById(R.id.mainLayout); //<-- you have to set the id property of the RelativeLayout on the xml file
mainLayout.addView(otherButton,buttonDeets);
}
和布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/mikesButton"
android:text="Button to press"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<TextView
android:text="Text to change"
android:id="@+id/mikesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/mikesButton"
android:layout_centerHorizontal="true"
android:textAppearance="?android:textAppearanceLarge"/>
</RelativeLayout>
@ geert-berkers我偷了您的xml导致太懒了以至于无法自己做一个:p
编辑2:已更改的问题
您现在遇到的错误是由于:
////////// Add widgets to layout and their rules///////////
myLayout.addView(mikesButton, buttonDeets); //Second param shows android the rules of how it is layed out
myLayout.addView(mikesText, textdeets);
在这里,您说的是要将mikesButton和mikesText添加到通过代码创建的myLayout中,但是按钮已经是从xml(使用
setContentView(R.layout.activity_main);
)加载的布局的一部分。我不明白您要通过这样做来实现什么。如果要通过代码添加新视图,请不要使用
findViewById(R.id.mikesButton);
,而应使用new Button(this)
创建一个新实例。 findViewById尝试查找已经在视图组的层次结构中的视图,在这种情况下,视图组是活动的布局。看一下// TODO:我给您的部分代码,注意与您在此处所做的不同。
还要避免在不同的对象上使用相同的引用,因为这会使您感到困惑。
别 :
this.mikesButton = (Button) findViewById(R.id.mikesButton);
// Later ...
this.mikesButton = new Button(this);
// So now you lost the reference to the previous object
改为:
this.mikesButton = (Button) findViewById(R.id.mikesButton);
// Later ...
Button otherButton = new Button(this);
// You can still reference the precious object and u know that mikesButton is the one you loaded from the xml layout