I haven't beeen able to find the answer to the following question:
How do I get data from View A to View B, with View A and View B in the same LinearLayout? Is this even possible? Do I need to start working with threads?
I haven't been able to get the correct search phrase I guess, I'm probably not the first person that wants to do this, but I can't find it :(
Below is what I use now to create the views. In the TargetTrainer (which extends View) I'm letting the user give some input, and I'd like to be able to give feedback to the user in the TextView. How would I for instance show the coordinates of the onTouchEvent of TargetTrainer in the TextView?
Below is a clipped/simplified version of my program.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
LinearLayout linear;
linear = new LinearLayout(this);
linear.setOrientation(LinearLayout.VERTICAL);
TextView text = new TextView(this);
text.setText("Test");
linear.addView(text);
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
TargetTrainer t = new TargetTrainer(this, width, height);
linear.addView(t);
setContentView(linear);
}
As I can see from the snippet, you already pass Context in the constructor new TargetTrainer(this, width, height). Assuming that the code you provided is from activity called BaseActivity create reference to BaseActivity in the TargetTrainer constructor and call the update method from TargetTrainer.
public TargetTrainer extends View {
....
BaseActivity mBaseActivity = null;
public MyView(Context context, int width, int height) {
....
mBaseActivity = (BaseACtivity)context;
....
}
....
private void update(String text)
{
mBaseActivity.updateTextView(text);
}
}
In BaseActivity create updateTextView:
public void updateTextView(String updateText){
text.setText(updateText);
}
You should set the id of that TextView, listen to the touch events in your TargetTrainer, and when one occures, you use
final TextView tv = (TextView)TargetTrainer.this.findViewById(R.id.myTextView);
tv.setText(touchEvent.toString());
That's it.
Update
It would be much cleaner, if you'd build your main layout from an xml source.
You need to create a new layout xml inside the /res/layout that looks like the one you're creating inside your onCreate method:
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/myTextView" android:text="Test"
android:layout_width="fill_parent" android:layout_height="wrap_content" />
<!-- change the your.package part to match the package declaration
of your TargetTrainer class -->
<your.package.TargetTrainer android:id="#+id/myTargetTrainer"
android:layout_width="fill_parent" android:layout_height="fill_parent" />
</LinearLayout>
This way a new entry will be placed inside your R class' static layout class with the name main.
You can reference it by R.layout.main.
Note, that in this xml you have id attributes defined for both
your TextView: myTextView, and
your TargetTrainer:
'myTargetTrainer'.
The #+id inside the xml tag means that you are creating a new id with the name after the '/' sign.
This also will create new members inside your R class' static id class with the names you've provided: myTextView and myTargetTrainer that are accessible from now on from anywhere in your code.
If you've built this xml, your onCreate method will look like this:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// attach the OnTouchListener to your TargetTrainer view:
(TargetTrainer)findViewById(R.id.myTargetTrainer).setOnTouchListener(this);
}
You also have to extend your main activity class to implement the View.OnTouchListener interface, and add the necessary method at the end of your class:
#Override
public boolean onTouch(View view, MotionEvent event)
{
//note, that here the view parameter is the view the touch event has been dispatched to
final TextView tv = (TextView)findViewById(R.id.myTextView);
tv.setText(event.toString());
return true; //or false, if you are dealing further with this event in parent classes
}
Related
Background: I am writing an Android app, mostly following instructions from the official developer guides. I have some experience with writing Java code but little with xml and Android.
Question: I would like to pass information from variables in my static class "PlaceholderFragment" (which is contained by my "BoardContainer" class) to my fragment layout file "fragment_board.xml". PlaceholderFragment looks like this (mostly unedited after Eclipse created it for me):
public static class PlaceholderFragment extends Fragment {
public int nButtons = 2;
public static class PlaceholderFragment extends Fragment {
private int nButtons = 2;
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_board,
container, false);
return rootView;
}
}
(other lifecycle callbacks have not yet been implemented).
Now my fragment_board.xml is like this:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.exampletest.MainGame$PlaceholderFragment" >
<ImageButton
android:id="#+id/imageButton1"
android:layout_width="49dp"
android:layout_height="49dp"
android:contentDescription="#null"
android:onClick="buttonPressed" //not yet implemented
android:src="#drawable/grid2" />
</RelativeLayout>
Here I would like to use the int instance variable nButtons so that, for example, if nButtons==7, then we get android:src="#drawable/grid7 instead of grid2, or that the layout file will contain seven ImageButtons instead of just one, and so forth. In other words, how do I make the xml file read and understand the instance variables from its corresponding class?
Unfortunately XML files can not read and understand the variables from its corresponding class. Instead we can alter them programatically by obtaining a handle to components contained within XML files in a class file and altering them like this:
ImageButton imgHandle = (ImageButton) findViewById(R.id.imageButton1);
if(nButtons == 7) {
imgHandle.setImageResource(R.id.grid7);
}
In a fragment you're going to need to use rootView inside of your onCreateView method:
ImageButton imgHandle = (ImageButton)rootView.findViewById(R.id.imageButton1);
I'm trying to make a bull's eye with random color, and instead of circles I will use squares.
But the thing is that when I run the app on the emulator and when he starts the new activity it stops responding.
This is the main activity, the one that starts the DrawActivity.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent coiso = new Intent(this, Draw.class);
startActivity(coiso);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
And this is the Draw activity, the one that I want to start. (It doesn't have the things that I want to do. Because I can't, the problem is ahead)
public class Draw extends View {
public Draw(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
}
}
Can someone help me? Sorry for the english.
You have this
public class Draw extends View
Your class does not extend Activity
Instead you can do as below
Draw draw = new Draw(this);
setContentView(draw);
Or have a layout linear or relative and place it where you like add your Draw view to the layout after initializing.
setContentView(R.layout.activity_main);
LinearLayout ll = (LinearLayout)findViewById(R.id.linearLayout);
// linear layout or relative layout in activity_main.xml.
// place the layout ahere you want along with other views
Draw draw = new Draw(this);
ll.addView(draw);
// add your customview to linearlayout
Edit:
Remove this
Intent coiso = new Intent(this, Draw.class);
startActivity(coiso);
In your activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
// customize linear layout to your needs.
<LinearLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:id="#+id/linearLayout"
android:orientation="vertical" >
</LinearLayout>
// other widgets
</RelativeLayout>
In your onCreate
setContentView(R.layout.activity_main);
LinearLayout ll = (LinearLayout)findViewById(R.id.linearLayout);
Draw draw = new Draw(this);
ll.addView(draw);
startActivity requires an activity. I would suggest going through the docs
http://developer.android.com/reference/android/app/Activity.html#startActivity(android.content.Intent)
Your Draw class needs to extend Activity rather than View. As you want to start a new Activity, the Draw class, this means that this should extend Activity. Also, you need to Override onCreate() within the Draw class.
If your Draw class is a View, then I would suggest that you add the view to the Layout that you are using using the addView()
You need to make sure that you change Draw extends Activity
You cant intent to a new activity with no layout and no OnCreate As far as I know.
try creating a regular activity which extends Activity and implement your Draw there.
public class DrawActivity extends Activity {
#SuppressLint("ShowToast")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
Toast.makeText(DrawActivity.this, "YO", Toast.LENGTH_LONG);
}
and from there implement your draw functions.
or create a JAVA class which implements your draw needs and use it in main screen.
I have an Android app where i'm using tabs (with ActionBarSherlock). So my main activity creates the tabs for me and from there i load in the fragment layouts.
In my MainActivity.java i create a tab (this is just a snippet):
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(
bar.newTab().setText("Fragment 1"),
MainMenuFragment.class, null);
My MainMenu.java looks like this:
public class MainMenuFragment extends SherlockFragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.mainmenu_fragment, container, false);
return view;
}
public void showMainMenu(View view)
{
Log.e("app", "olol: button!"); // never called!!
}
}
And this is mainmenu_fragment
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000" >
<Button
android:id="#+id/btnMenu"
android:layout_width="170dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="41dp"
android:text="#string/mainmenu"
android:onClick="showMainMenu" />
</RelativeLayout>
Now all i have to do is place the method showMainMenu(View view) somewhere. I thought this would go in the corresponding java file (MainMenuFragment.java in my case). But it only works when i put the method in the MainAvtivity.java file.
That means that all my button actions from all kinds of fragment layouts will go in one (the main) java file. Why can't i simply place it inside the java file that calls the Fragment layout..??
The short answers is (like already pointed out), you can't.
The only way to do this is by creating an onClick even listener. In the MainMenuFragment.java in the onCreate method, do something like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.scan_fragment, container, false);
Button menuButton = (Button)view.findViewById(R.id.btnMenu);
menuButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.e("app", "onclick listener");
}
});
return view;
}
You can remove the onClick attribute from the layout xml.
Now all I have to do is place the method showMainMenu() somewhere - this is wrong. Please, refer to the documentation of android:onClick :
For instance, if you specify android:onClick="sayHello", you must declare a public void sayHello(View v) method of your context (typically, your Activity).
Seems You cannot place your callback somewhere, because framework won't be able to find that callback. If You're defining it inside Activity (which is actually, a Context), it's possible for View to find it back. Actually, View.java contains the following code:
case R.styleable.View_onClick:
if (context.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot " + "be used within a restricted context");
}
final String handlerName = a.getString(attr);
mHandler = getContext().getClass().getMethod(handlerName, View.class);
...
mHandler.invoke(getContext(), View.this);
Seems it's the only possible way to call callback defined in layout file with current android:onClick attribute specification.
I solved this using the following:
Fragment xml contains
android:onClick="myFunction"
Activity Contains
public void myFunction(View v)
{ getSupportFragmentManager().findViewById/Tag(...).myFunction(v); }
Fragment Code can then implement as below to have access to local data
public void myFunction(View v) {...}
Hope this helps.
I've been trying to create a simple class that implements the ViewSwitcher.ViewFactory interface basing on the project developed in "Sams Teach Yourself Android Application Development in 24 Hours". In the example the makeView() method inflates a layout in order to obtain a View. However, I wanted to do it programmatically and it didn't work.
The onCreate() method of the activity looks like this:
private TextSwitcher mQuestionText;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
mQuestionText = (TextSwitcher) findViewById(R.id.MyTextSwitcher);
mQuestionText.setFactory(new MyTextSwitcherFactory());
mQuestionText.setCurrentText("blablabla");
}
The proposed solution goes like this:
private class MyTextSwitcherFactory implements ViewSwitcher.ViewFactory {
public View makeView() {
TextView textView = (TextView) LayoutInflater.from(
getApplicationContext()).inflate(
R.layout.text_switcher_view,
mQuestionText, false);
return textView;
}
}
The resource file is:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:textColor="#color/title_color"
android:textSize="#dimen/game_question_size"
android:gravity="center"
android:text="Testing String"
android:layout_height="match_parent"
android:padding="10dp">
</TextView>
While I wanted to it like this:
private class MyImageSwitcherFactory implements ViewSwitcher.ViewFactory {
public View makeView() {
TextView textView = new TextView(getApplicationContext());
textView.setLayoutParams(new TextSwitcher.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
textView.setTextColor(R.color.title_color);
textView.setTextSize(R.dimen.game_question_size);
textView.setGravity(Gravity.CENTER);
textView.setText("Test");
return textView;
}
}
I get the "blablabla" text displayed when I use the inflate method but not doing it programmatically. Could you point to an error in my code, please?
mQuestionText = (TextSwitcher) findViewById(R.id.MyTextSwitcher);
You're finding the view by the id MyTextSwitcher. Make sure you set that id if you're creating the view programmatically.
view.setId(R.id.MyTextSwitcher);
Update:
Whoops, didn't read your code carefully enough. You're right, since you're inflating from the XML, your ID should be set properly already. What you probably are missing is actually adding the view to the view hierarchy. You need to find a parent ViewGroup (e.g. a LinearLayout or a 'RelativeLayout, etc.) under which you want to putMyTextSwitcher, let's call itroot` and add it with something like:
root.addView(view);
I found out what was wrong with the code I provided. This is wrong since it gives the ID of the resource as the function parameter instead of the value itself.
textView.setTextColor(R.color.title_color);
textView.setTextSize(R.dimen.game_question_size);
This is correct:
textView.setTextColor(getApplicationContext().getResources().getColor(R.color.title_color));
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, getApplicationContext().getResources().getDimension(R.dimen.game_question_size));
I'm looking now a few days for a solution for clickable items in a listView.
First I came across this:
developer.android.com/resources/articles/touch-mode.html
and found that it's doesn't have the "normal" onListItemClick() behavouir.
Then I came across of this code:
http://www.androidsnippets.org/snippets/125/
// LINE 296-321
#Override
protected ViewHolder createHolder(View v) {
// createHolder will be called only as long, as the ListView is not filled
// entirely. That is, where we gain our performance:
// We use the relatively costly findViewById() methods and
// bind the view's reference to the holder objects.
TextView text = (TextView) v.findViewById(R.id.listitem_text);
ImageView icon = (ImageView) v.findViewById(R.id.listitem_icon);
ViewHolder mvh = new MyViewHolder(text, icon);
// Additionally, we make some icons clickable
// Mind, that item becomes clickable, when adding a click listener (see API)
// so, it is not necessary to use the android:clickable attribute in XML
icon.setOnClickListener(new ClickableListAdapter.OnClickListener(mvh) {
public void onClick(View v, ViewHolder viewHolder) {
// we toggle the enabled state and also switch the icon
MyViewHolder mvh = (MyViewHolder) viewHolder;
MyData mo = (MyData) mvh.data;
mo.enable = !mo.enable; // toggle
ImageView icon = (ImageView) v;
icon.setImageBitmap(
mo.enable ? ClickableListItemActivity.this.mIconEnabled
: ClickableListItemActivity.this.mIconDisabled);
}
});
While debugging I noticed the parameter View v is a TextView and not a "normal" View and then of course:
TextView text = (TextView) v.findViewById(R.id.listitem_text);
returnes null and I get a NullPointerException...
Any ideas why? And how I can solve this?
Thanks in advance! :)
How do you create your instance of ClickableListAdapter ?
When you create your list adapter, you have to pass a resource id viewId, this should be a layout which will be inflated later.
public ClickableListAdapter(Context context, int viewid, List objects) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
mDataObjects = objects;
mViewId = viewid;
Below, the code inflate the xml layout passed to the constructor and call createHolder.
view = mInflater.inflate(mViewId, null);
// call the user's implementation
holder = createHolder(view);
So make sure that when instantiating your ClickableListAdapter, you pass a layout instead of an id
Edit
You have to create a xml layout with the following which is taken from the link you have provided:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
>
<TextView android:text="Text" android:id="#+id/listitem_text"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
></TextView>
<ImageView android:id="#+id/listitem_icon"
android:src="#drawable/globe2_32x32"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="32px"
android:maxHeight="32px"
>
</ImageView>
</LinearLayout>
If you call it mylistrow.xml in the layout directory, so you construct your adapter as :
adapter = new MyClickableChannelListAdapter(this, R.layout.mylistrow, channelList);
setListAdapter(adapter);
List items should be clickable right out of the box. You can check how lists are coded by looking at ApiDemos project code. It should be present on your local machine since it is a part of the SDK. I have it at <root_sdk_folder>\platforms\android-2.0.1\samples\ApiDemos.