Sometimes I need to do some operations(e.g. changing layout) when the activity is just showing. What I do now is using post():
public class MyActivity extends Activity {
#Override
public void onCreate() {
...
container.post(new Runnable(){
resize(container);
});
}
}
Is there any lifecycle method like onCreate can be used to simplify the code, that I don't need to call post?
#Override
public void onX() {
resize(container);
}
I think you mean do something after the UI is displayed.
Using a global layout listener has always worked well for me. It has the advantage of being able to remeasure things if the layout is changed, e.g. if something is set to View.GONE or child views are added/removed.
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// inflate your main layout here (use RelativeLayout or whatever your root ViewGroup type is
LinearLayout mainLayout = (LinearLayout ) this.getLayoutInflater().inflate(R.layout.main, null);
// set a global layout listener which will be called when the layout pass is completed and the view is drawn
mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
// at this point, the UI is fully displayed
}
}
);
setContentView(mainLayout);
http://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener.html
Related
I have created a MainActivity, it has a layout which has different elements; e.g: TextBox, EditBox, Button.
I have created a ChildActivity that is extending from MainActivity, ChildActivity also has a Layout.
My question is, can i use the layout elements of MainActivity and display them in my ChildActivity
The elements you can use depend on what layout file you pass to setContentView(R.layout.my_layout_file); in the onCreate. So yes you can use them in both if you give both activities the same layout file, but they will be treated like separate layouts. E.g. if you set some text in a textview in Main, it will not show in Child.
yes you can access the parent-activity element through add child-activity layout in parent-activity layout.this way you can inflate both layout in child-activity.
ViewGroup viewGroup; is child layout container in parent-activity.
like
parent activity or NormalActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
ViewGroup viewGroup;
protected void onCreate(Bundle savedInstanceState,int res) {
onCreate(savedInstanceState);
viewGroup = (ViewGroup) findViewById(R.id.childContainer);
viewGroup.addView(LayoutInflater.from(this).inflate(res, viewGroup,false));
}
}
Child Activity
public class ChildActivity extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState,R.layout.child_layout);
}
}
The problem is MainActivity starts with a setContentView with a layout.xml. We can add buttons or anything to the layout and code in in the MainActivity class but when I try to code the buttons of another layout in the same Activity the app forces stop . Whats wrong ?
Ok I found out that is because of the context.
When you try to change other activity you have to use layoutinflater. Example below
LayoutInflater inflater = getLayoutInflater();
View myLayout = inflater.inflate(R.layout.my_layout, null);
To work with widgets inside it like buttons or anything .
Button b = mylayout.findViewById(R.id.button);
b.setText("Successfully changed");
Now you can use myLayout as your changed layout.
Please sent me your Activities
What the text of problem ?
You may write next code to go to another activity
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getApplicationContext(),nameActivity.class));
}
});
Where button is name of your button
See that you xml-file doesnt have any mistakes
You are getting a crash because you are trying to access the layout when it is not inflated. In other words, you must call setContentView() on an Activity, or inflater.inflate() on a Fragment to instantiate the view and make the elements accessible for manipulation. So if you want to add buttons to another Activity, you would need to call its onCreate() and setContentView() before you can add buttons to it.
EDIT: In response to comments...
In order to access/manipulate/modify elements in a layout at runtime, they must first be instantiated, which happens when the view is inflated. So to add a button to an Activity at runtime, you would do it in the onCreate() method after calling setContentView() like this:
Keep in mind this is the onCreate() of your SECOND activity...not your main Activity. So your main activity would start this Activity, then the button would get created during the setup of the second Activity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_second_activity;
Button button = new Button(this);
button.setText("Your New Button");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("NEW BUTTON", "I just clicked my new button!");
}
});
RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.layout_in_your_second_activity);
relativeLayout.addView(button);
}
If you are using a Fragment to display your UI, you can't access your UI elements until you have inflated your layout, which happens in the onCreateView() method. So you would do something like this in your Fragment code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.your_fragment_layout, container, false);
RelativeLayout relativeLayout = (RelativeLayout) view.findViewById(R.id.container_layout_that_holds_button);
//You would get your context from an onAttach() Override
Button button = new Button(context);
button.setText("Your New Button");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("NEW BUTTON", "I just clicked my new button!");
}
});
relativeLayout.addView(button);
return view;
}
You're likely getting a NullPointerException when you try to manipulate your layouts before they are created. Keep in mind that even if you have an XML file with layouts specified within, the actual objects for those elements won't be created until the system decides it needs them, which happens when you actually try to display the view.
In my PreferenceFragment there is a ListPreference which is programmatically populated at onCreate(). Thus, there is a little lag at the fragment start. In order to avoid it I would like to populate the ListPreference only when the preference has been pressed, and put a indeterminate ProgressBar while the content is loading.
How could I implement this? Do I really need to rewrite the adapter? How can I get the view for the ListPreference to pass to View.OnClickListener?
I hope this is not a trivial question, I have googled for a while but I didn't understand how should I actually implement the whole thing.
Thank you in advance.
I've created a custom PreferenceFragment for this.
You can extend this one instead of a PreferenceFragment and delay your call to addPreferencesFromResource till after all loading is done, which will then hide the ProgressBar and display your content.
public class ProgressBarPreferenceFragment extends PreferenceFragment {
private FrameLayout progress;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
showLoading((ViewGroup) view);
return view;
}
#Override
public void addPreferencesFromIntent(Intent intent) {
super.addPreferencesFromIntent(intent);
hideLoading();
}
#Override
public void addPreferencesFromResource(int preferencesResId) {
super.addPreferencesFromResource(preferencesResId);
hideLoading();
}
private void hideLoading() {
ViewGroup root = (ViewGroup) getView();
if ((root != null) && (progress != null)) {
root.removeView(progress);
}
}
private void showLoading(ViewGroup root) {
progress = new FrameLayout(root.getContext());
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER;
progress.addView(new ProgressBar(root.getContext()), lp);
LayoutParams lp2 = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
root.addView(progress, lp2);
}
}
You could use an AsyncTask to populate your ListPreference asynchronously and then remove the indeterminate progress bar upon completion.
First, extend AsyncTask like so:
private class PopulateListPreferenceTask extends AsyncTask<CharSequence, Void, Void> {
protected Long doInBackground(CharSequence... entries) {
// Code to populate ListPreference in here
}
protected void onPostExecute() {
// Add code here if necessary to retrieve the progress bar view, i.e. findViewById
myIntederminateProgressBar.setVisibility(View.GONE);
}
}
Have your indeterminate progress bar shown initially. Then, in your fragment's onActivityCreated method, call:
new PopulateListPreferenceTask().execute(/*CharSequence entries go here*/);
A couple notes:
I am assuming that you would want to provide Charsequences as
input, but you can use any other type.
If you need the AsyncTask to receive the Activity context you can
overload the constructor to receive it as a parameter and then
store it in a field.
I used this code, but when i click on activity at runtime, it never hits in OnTouch() method. Can someone guide me what i am doing wrong? Should i need to setcontentview of this activity? Actually i want the coordinates of activity where user touch during execution.
public class TouchTestAppActivity extends Activity implements OnTouchListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.touch);
}
#Override
public boolean onTouch(View arg0, MotionEvent arg1)
{
// TODO Auto-generated method stub
String test = "hello";
}
}
UPDATE:
You need to do this :
In your XML layout file, you need an ID for the root view: android:id="#+id/myView"
In youer onCreate() method, write this:
LinearView v= (LinearView) findViewById(R.id.myView);
v.setOnTouchListener(this);
Assuming that your root view is a LinearView
You should the onTouchListener to relevant GUI components.
For example:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.touch);
TextView someView = (TextView)findViewById(R.id.some_view_from_layout_xml);
someView.setOnTouchListener(this); // "this" is the activity which is also OnTouchListener
}
You have to add a the listener using setOnTouchListener() otherwise who will give call to your onTouch method. any listener works on any view. so you have to add the listener to the view eg button.setOnTouchListener(this);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View vi = inflater.inflate(R.layout.yourxml, null);
setCOntentView(vi);
vi.setOnTouchListener(this);
In onCreate, you need to set the content view (just uncommenting the second line should probably work) and then you need to set your OnTouchListener (your activity) as the onTouchListener for a view in your application.
Let's say you've got a view in your layout called "MainView"; it would look something like this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
View view = findViewById(R.id.MainView);
view.setOnTouchListener(this);
}
This article has a good example:
http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-2-building-the-touch-example/1763
MainActivity.java:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setTitle(R.string.app_name);
setContentView(new SampleView(this));
}
}
SampleView.java:
public class SampleView extends View {
#Override
protected void onDraw(Canvas canvas) {
if (certaincondition = true) {
//add elements to canvas etc
} else {
//How do I do the below? The layout is defined in xml.
//I do not want to use Intent. Please help me
//create a layout from resource R.layout.idAbout and transfer control.
}
}
}
Use a layout inflater:
View newRootViewElement;
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
newRootViewElement= li.inflate(R.layout.idAbout, null);
You can inflate a layout using
View.inflate(getContext(), R.layout.idAbout, viewParent);
where viewParent is a ViewParent that will be the parent of the inflated view (and can be null).
But what are you trying to do? It's more than a little odd to start a new activity or to modify the view hierarchy from within onDraw(). You might want to post a runnable to a Handler that will do what you want on the next cycle of the event loop. To start a new activity (such as displaying “About” info for the app) you should take a look at the Intent class.