I have a View that I would like a TextView to pop up over when an event occurs. I have done this before (a long time ago) but can't remember how I did it...
My code is for the View element. Upon adding the TextView, I would like it to show over the top of the View.
public class test extends View {
public test(Context context) {
super(context);
setBackgroundColor(Color.RED);
}
TextView tv;
public void adText(TextView tv){
this.tv =tv;
tv.setVisibility(tv.VISIBLE);
}
}
http://www.curious-creature.org/2009/03/01/android-layout-tricks-3-optimize-part-1/
Solves it. Someone delete that wierd comment please...
Related
In the galleryView onItemSelected I call setText that change the text for a textview thats part of the main layout:
#Override
public void onItemSelected(EcoGalleryAdapterView<?> parent, View view, int position, long id) {
// --- run asyncTask to update gallery view here
TextView myTextView = (TextView) findViewById(R.id.myTextView);
myTextView.setText("position is: ": position);
}
if I left everything as it is and just removed myTextView.setText the gallery works as expected but if I kept it then when scrolling the gallery snaps to the selected position really fast in an ugly way. What could be the issue?
"Ugly" is a pretty subjective term for describing a user interface transition.
However, it sounds as though what you want is a custom animation when an item is selected. onItemSelected() is called before the layout happens, so you can animate your Gallery or individual Views however you want in this method.
I would suggest reading the Animation and Graphics documentation from the Android developer documentation to more fully understand animations and to help decide what you actually want.
The code will vary depending on what you decide you want it to look like and what version of Android you are targeting. A simple View animation that will fade the selected view in might look something like this:
public void onItemSelected(EcoGalleryAdapterView<?> parent, View view,
int position, long id) {
view.setAnimation(new AlphaAnimation(0, 1));
}
// try this
TextView myTextView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.image_full);
myTextView = (TextView) findViewById(R.id.myTextView);
}
#Override
public void onItemSelected(EcoGalleryAdapterView<?> parent, View view, int position, long id) {
// --- run asyncTask to update gallery view here
myTextView.setText("position is :"+ position);
myTextView.invalidate();
}
The setText commands sits on the UI Thread, maybe it's taking a higher priority or something from the current Gallery animation which disrupts it from acting as it should.
try setting your setText inside a handler:
new Handler().post(new Runnable() {
#Override
public void run() {
myTextView.setText("position is: ": position);
}
});
I am interested in populating a screen/activity with a user defined number of same views. Each view will have the exact same layout: couple TextViews and few Buttons. The thing is that each button will control what each TextView will display.
The way I was thinking to implement it was to have one XML and one Java class. Then dependimg on the number the user inputs, populate the screen with that many same views (using a for loop). The question is, can it be done? how? am I thinking about it in the right way?
Please help with any input or thoughts, code examples will be great too.
of course it can be done.
I think the easiest for your situation, plus you can then easily extend, is to create some helper functions that take care of:
1) creating a empty screen
2) create a button for a screen
3) create a textview for a screen
and finally
4) create a screen and populate it
You have to decide the proper Root element for your Views, depending on the child arragement you need. For simplicity let's choose a LinearLayout, but for a RelativeLayout or TableLayout the example is the same, it only changes that when you add the elements, you have to use additional parameters to properly place them.
Note that the function to create an empty custom view returns a ViewGroup ("where all layouts derive from"). This way, you always work with ViewGroups and just define the screen layout type once, inside createCustomView. So you can change the type of screens just there, and the rest of code will work ...
Here is some code for your inspiration:
private ViewGroup createCustomView(Context context) {
LinearLayout myCoolNewView=new LinearLayout(context); // or RelativeLayout, etc..
return myCoolNewView;
}
private Button createButton(Context context, String buttonText) {
Button newButton=new Button(context);
newButton.setText(buttonText);
return newButton;
}
private TextView createText(Context context, String initialText) {
TextView newText=new TextView(context);
newText.setText(buttonText);
return newText;
}
private ViewGroup createScreen(Context context, int numberOfButtons, int numberOfTextfields) {
ViewGroup newScreen=createCustomView(context);
TextView[] textViews=new TextView[numberOfTextFields];
for (int i=0; i<numberOfTextfields; i++) {
textViews[i]=createText(context, "hi i am text "+i);
newScreen.addView(textViews[i]); // you ideally provide here layoutparams to properly place your buttons
}
for (int j=0; i<numberOfButtons; j++) {
Button button=createButton(context, "hi i am button "+j);
button.setOnClickListener(new OnClickListener() {
public void onClick (View clickedView) {
// here you have a button keypress and you know all the textviews
textView[i%j].setText("hey you pressed me");
}
});
newScreen.addView(button);
}
return newScreen;
}
So now you can:
ViewGroup screen1=createScreen(context, 10, 10);
ViewGroup screen2=createScreen(context, 5, 3);
ViewGroup screen3=createScreen(context, 2, 5);
and add the screens to a parent layout, to a ViewFlipper, to a ViewSwitcher, etc... like this:
ViewGroup parentLayoutOfAllScreens=findViewById(R.id.root_of_screens);
parentLayoutOfAllScreens.addView(screen1);
parentLayoutOfAllScreens.addView(screen2);
parentLayoutOfAllScreens.addView(screen3);
In the XML you just have to create the root layout, and name it root_of_screens...
good coding !!! I suppose there'll be some errors in the code above, just typed it here, but I hope you get the idea and tweak it to suit your needs!
EDIT : v2.0 : Extending a View
Create a new .java named "MyCoolScreen.java" or whatever name, in the same folder where your activity is (for simplicity):
package ........
public class MyCoolScreen extends LinearLayout {
/** Now every view holds its own buttons, and they are private, it's good for encapsulating */
private TextView[] mTextViews; // <-- as a convention, members should start with "m"
private Button[] mButtons;
private UserPressedButtons mUserPressedButtonsListener; // See below
/** The following constructors must always be present for a custom view, and must always call super */
public MyCoolScreen(Context context) {
// This is the constructor you will use when creating your view programmatically
super(context);
}
public MyCoolScreen(Context context, AttributeSet attrs) {
// This is the constructor Android calls when you include your custom view in an XML
// You can do this too!!
// The ATTRS will then include your numberofbuttons and numberoftextfields from the XML
// this is beyond the example, but read about it, it's interesting
super(context, attrs); // this MUST ALWAYS be here for custom views, or they will not work.
// it tells the parent view to continue the construction.
}
public MyCoolScreen(Context context, AttributeSet attrs, int defStyle) {
// Another constructor Android calls from the XML
super(context, attrs, defStyle);
}
/** We create an "init" method to initialize this view from outside */
public void init(int numberOfTextViews, int numberOfButtons) {
createScreen(numberOfTextViews, numberOfButtons);
}
/** This is the same */
private Button createButton(Context context, String buttonText) {
Button newButton=new Button(context);
newButton.setText(buttonText);
return newButton;
}
/** This is the same */
private TextView createText(Context context, String initialText) {
TextView newText=new TextView(context);
newText.setText(buttonText);
return newText;
}
/** We tweak this function so it doesnt return a view, but rather fills up this one :) */
private void createScreen(int numberOfButtons, int numberOfTextfields) {
ViewGroup newScreen=this; // It's this view the one we gonna fill up!
mTextViews=new TextView[numberOfTextfields];
mButtons=new Button[numberOfButtons];
Context context=getContext(); // Views always know their context after constructed
for (int i=0; i<numberOfTextfields; i++) {
mTextViews[i]=createText(context, "hi i am text "+i);
newScreen.addView(textViews[i]); // you ideally provide here layoutparams to properly place your buttons
}
for (int j=0; i<numberOfButtons; j++) {
Button button=createButton(context, "hi i am button "+j);
button.setId(j);
button.setOnClickListener(new OnClickListener() {
public void onClick (View clickedView) {
// here you have a button keypress and you know all the textviews
if (mUserPressedButtonsListener!=null) mUserPressedButtonsListener.OnButtonPressed(j);
textView[i%j].setText("hey you pressed me");
}
});
mButtons[j]=button;
newScreen.addView(button);
}
}
public interface UserPressedButtons {
public void OnButtonPressed(int buttonNumber);
}
public void setUserPressedButtonsListener (UserPressedButtons listener) {
mUserPressedButtonsListener=listener;
}
}
Ok, so now to use this, in your Activity you can do:
import ....... .MyCoolScreen;
import ....... .MyCoolScreen.UserPressedButtons;
.
.
.
MyCoolScreen screen1=new MyCoolScreen(context);
screen1.init(5,5); // initializes the screen.
myRootLayout.addView(screen1);
What's cool about this, is now functionality is totally encapsulated in your custom view. And it resides in another .java, so your activity code is very clean, and you can even expand the View functionality without making it ugly.
It's also a common practice to create interfaces and listeners for your views to communicate with the outside world, so for example, we can do:
screen1.setUserPressedButtonsListener(new MyCoolScreen.UserPressedButtons() {
#Override
public void OnButtonPressed (int number) {
// you know the user pressed button "number", and you can do stuff about it without
// having to include it inside the MyCoolScreen class. Of course in your example you
// don't need this at the moment, because the View will modify its textfield, but suppose
// one of the buttons is "rocket launch" , that is something you will handle at the activity level, ie.
if (number==ROCKET_LAUNCH) RocketLauncher.setTarget(10,10).launch(); // Your MyCoolScreen doesnt know how to launch rockets, but your activity maybe yes...
}
});
You can do all kinds of cool things with your new custom view. For example, you could define:
#Override
public void OnDraw(Canvas c) {
c.drawEllipse ...
c.drawRectangle ....
}
And you can paint circles, lines, etc... over your textfields & buttons :) For this to work, you have to put
setWillNotDraw(false) on the constructor.
There might be errors, just typed the code here, but I hope it helps you!
Add and Remove Views in Android Dynamically?
this will helps to you most...
This should be very easy to do, but somehow after some 15 minutes searching I still can't get the answer:
I want to make a custom Android View combining a TextView and a Button, plus some customized behaviors/methods, let's say when I click the button it should change the TextView to "Hello, world!".
I know that I'll have to extends the View class, and design the layout in a XML, then do some magic to link the two. Could you tell me what the magic is? I know how to do this in an Activity, but not in a custom View.
EDITED
Ok, so I found out I need to use a Inflater to inflate my class with the child views defined in a layout. Here's what I got:
public class MyView extends View {
private TextView text;
private Button button;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
View.inflate(context, R.layout.myview, null);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
text = (TextView) findViewById(R.id.text);
button = (Button) findViewById(R.id.button);
}
}
However, the text and button child views were null. Any idea? (The XML is very simple without any fancy edit, i just grabbed a TextView and a Button from the eclipse toolbar and throw in.)
Ok, so the answer to my own question is: (i) go get dinner, (ii) extends LinearLayout instead of View, this makes it a ViewGroup and thus can be passed into the inflate(...) method but don't have to override the onLayout(...) method. The updated code would be:
public class MyView extends LinearLayout {
private TextView text;
private Button button;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
View.inflate(context, R.layout.myview, this);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
text = (TextView) findViewById(R.id.text);
button = (Button) findViewById(R.id.button);
}
}
i have made one of these tap number games for android as a test project and for this i have made a gridview with about 20 buttons in it. when one of these buttons is pressed an animation is started. this runs fine for the first few times but than becomes slower and starts stuttering.
i assume it has something to do with the animation ressource as i use it several times at the same time but i dont know how to solve the problem.
as i want to remove the button from the gridview when the animation ends i wrapped the AnimationDrawable class to be able to set a Handler which is called at the end of the animation.
public void animate() {
setBackgroundResource(R.drawable.myanimation);
final AnimationDrawable anim = (AnimationDrawable) getBackground();
final BetterAnimationDrawable better = new BetterAnimationDrawable(anim);
better.setEndHandler(new EndHandler());
better.start();
}
thanks in advance
UPDATE:
#warpzit: thanks for your answer. it's not a handler for earch click but a handler for each button. the onclick method disables the button (so it can only be pressed once) and then calls animate(). actually theres not much more code i can post, the gridview adapters getView looks like this:
#Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final MySpecialButton sb = new MySpecialButton(getApplicationContext());
sb.setOnClickListener(new SpecialButtonClickListener());
return nv;
}
and the mentioned handler looks like this (its actually not removing the button but changing the background-drawable, sorry for that):
private class MySpecialHandler extends Handler {
public MySpecialHandler() {
}
#Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
final Bitmap bitmapMask = BitmapFactory.decodeResource(getResources(), R.drawable.aspecialmask);
final BitmapDrawable d = new BitmapDrawable(bitmapMask);
d.setColorFilter([someColor], Mode.MULTIPLY);
setBackgroundDrawable(d);
}
};
You make a new handler for each click? That gotta hurt... How about making just 1 for each button or something else far smarter (need to see more code to come with other suggestions).
Take a look at this example:
public class TestEditSoftKbdActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.editText1).setFocusable(false);
findViewById(R.id.editText1).setClickable(false);
findViewById(R.id.editText1).setEnabled(false);
findViewById(R.id.editText1).setFocusable(true);
findViewById(R.id.editText1).setClickable(true);
findViewById(R.id.editText1).setEnabled(true);
findViewById(R.id.editText1).invalidate();
findViewById(R.id.editText1).requestLayout();
}
}
After this sequence of calls the edit text view would no longer pop up its soft input method upon being touched :(
Could someone explain what is going wrong here?
If you want to close soft keyboard for your text view follow this link. Here is a solution for you. But you need to define your own TextView to do that. He suggests using;
public class NoImeEditText extends EditText {
public EditTextEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onCheckIsTextEditor() {
return false;
}
}
Hope it works.