I have this LinearLayout that is a child of a RelativeLayout along with a ListView among other things:
<LinearLayout
android:id="#+id/color_bar"
android:layout_alignParentBottom="true"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="16dp"
android:padding="0dp"
android:orientation="horizontal"
>
<TextView
android:id="#+id/space_used_bar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#006688"
android:padding="0dp"
/>
<TextView
android:id="#+id/space_free_bar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#444444"
android:padding="0dp"
/>
</LinearLayout>
I don't intend to put any text in those TextViews; they are simply there for their background color values. I want to set the width's of these two TextViews programmatically, which I can do, but the problem is that the first time the LinearLayout is presented, it is not drawn. It has no size and I also cannot see the TextViews contained within it. When the user does almost anything (e.g. lock the screen, press the home button, click a list item, select an options item, etc.) the TextViews display properly. It's just that at the first moment when the activity opens, the TextViews and the Layout doesn't show up at all. Does anyone have any idea what the problem might be?
P.S. I have already tried calling invalidate on the LinearLayout as well as the individual TextViews.
EDIT: Here are the callbacks
#Override
public void onCreate(Bundle savedInstanceState)
{
//Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setContentView(R.layout.browser);
topMenu = getActionBar();
lv = (ListView) findViewById(R.id.file_list);
spaceUsedBar = (TextView) findViewById(R.id.space_used_bar);
spaceFreeBar = (TextView) findViewById(R.id.space_free_bar);
spaceUsed = (TextView) findViewById(R.id.space_used);
spaceFree = (TextView) findViewById(R.id.space_free);
colorBar = (LinearLayout) findViewById(R.id.color_bar);
stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
if (savedInstanceState == null)
{
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
currentDirectory = externalStorageDirectory;
else
{
currentDirectory = new File(ROOT_DIR);
Toast t = Toast.makeText(c, R.string.not_mounted, Toast.LENGTH_SHORT);
t.show();
}
}
else
{
currentDirectory = new File(savedInstanceState.getString("savedPath"));
int savedPosition = savedInstanceState.getInt("savedPosition");
int savedListTop = savedInstanceState.getInt("savedListTop");
if (savedPosition >= 0)
lv.setSelectionFromTop(savedPosition, savedListTop);
}
}
#Override
public void onStart()
{
//Log.d(TAG, "onStart()");
super.onStart();
lv.setOnItemClickListener(this);
lv.setMultiChoiceModeListener(this);
browseTo(currentDirectory);
}
#Override
public void onResume()
{
//Log.d(TAG, "onResume()");
super.onResume();
}
I guess that you haven't redrawn the layout after setting a new width for the TextViews and when the system redraws the layout after the user leaves then returns (locking the screen, home button, orientation change, etc). But I don't see your onCreate() and onResume() code, so it is only a guess...
I'm not sure if this will work but try one of the following (on the textviews). For instance you assign it some initial width or weight, and then adjust it accordingly programmatically when that code executes...
android:layout_width="40dp"
If you want them to take up a percent of the screen instead use the weight attribute:
android:layout_weight="2"
Related
I have a UI with some EditTexts in it and this set of edittexts can repeat number of times (not too much but 3 - 10 times max) based on the number of items in the list.
User can edit/modify/delete the item or edit the value of the edit texts. Currently I am doing this manually with "AddView/RemoveView", manually handling the states etc, however it is a lot of work as I have many scenarios like this.
We have a web app with the very same functionalities and we are using AngularJS to deal with all these, which, as you know is amazingly easy.
is there any closer way to bind the axml/xml view with a collection (may be an Observable collection and at least from the code behind) that will take care of collection changes as well as the individual field changes without me doing all this manually. In some scenarios I have to display images as well.
Also, I tried using a ListView, however it doesn't work as I would expect it to work.
is there any closer way to bind the axml/xml view with a collection (may be an Observable collection and at least from the code behind) that will take care of collection changes as well as the individual field changes without me doing all this manually.
The answer is no, there isn't. Android's views have to be bound to certain context/activity when they are created. They can't be isolated, so add/remove the EditTexts have to be implemented by yourself.
Currently, the closest way to your requirement is to create an ObservableCollection and listen for the CollectionChanged event and when CollectionChanged add/remove the view in your container:
[Activity(Label = "Demo", MainLauncher = true)]
public class MainActivity : Activity
{
Button btnAdd;
ObservableCollection<View> oc;
LinearLayout container;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
btnAdd = FindViewById<Button>(Resource.Id.btnAdd);
btnAdd.Click += BtnAdd_Click;
GenerateET(Resource.Id.container, this, 3);
}
private void BtnAdd_Click(object sender, System.EventArgs e)
{
EditText et = new EditText(this);
et.Text = "test";
et.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
oc.Add(et);
}
public void GenerateET(int resId, Activity activity,int num)
{
//create an observable collection
oc = new ObservableCollection<View>();
container = activity.FindViewById<LinearLayout>(resId);
for (int i = 0; i < num; i++)
{
EditText et = new EditText(activity);
et.Text = "test";
et.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
container.AddView(et);
oc.Add(et);
}
oc.CollectionChanged += Oc_CollectionChanged;
}
private void Oc_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
for (int i = 0; i < e.NewItems.Count; i++)
{
//add the view manually
container.AddView((View)e.NewItems[i]);
}
}
}
}
Main.axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
<Button
android:id="#+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add EditText"/>
</LinearLayout>
Hi I am working on writing my first usable android app. I have the following query , is there a way to populate values of a flied , based on value selected in a spinner.
e.g When country A is selected , 3 values are shown .
But when country B is selected, only 2 values are shown.
Is there a way to achieve this on Android screen? can someone provide some examples or point me in the right direction.
I think this example can help you not sure. I am creating a linear layout on which I will add all option. I am managing options in a hashmap. You can change according to your requirement.
Here is my main Activity:
public class MainActivity extends Activity {
HashMap <String, CheckBox> options = new HashMap<String, CheckBox>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int number_of_options = 2;
for (int i = 0; i < number_of_options; i ++) {
create_view("option " + i);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void create_view(String option)
{
LinearLayout layout = new LinearLayout(getApplicationContext());
layout.setOrientation(LinearLayout.VERTICAL);
TextView text_option = new TextView(getApplicationContext());
text_option.setText(option);
CheckBox check_box = new CheckBox(getApplicationContext());
layout.addView(text_option);
layout.addView(check_box);
LinearLayout inner_layout = (LinearLayout) findViewById(R.id.linear_layout);
inner_layout.addView(layout);
options.put(option, check_box);
}
}
create_view will create options for you.
Here is my XML layout:
<Spinner
android:id="#+id/spinner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="28dp" />
<LinearLayout
android:id="#+id/linear_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/spinner1"
android:layout_below="#+id/spinner1"
android:orientation="horizontal" >
</LinearLayout>
I am simply creating a linear layout and adding options on it. If you are having any doubt then you may ask I will try to help.
I am not managing margin between options.
This question has been asked several times, but everyone gives the reason for why this occurs (i.e. calculation occurs before the layout is laid). But I need the solution for this. I tried getBottom();, getTop();, getLocationOnScreen(int[] location);. But all returns the value Zero (0). I even tried giving these in onStart();, to give time for layout to be laid, but no luck.
Here is my code:
TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.textView1);
Log.d("getBottom :", Integer.toString(tv.getBottom()));
Log.d("gettop :", Integer.toString(tv.getTop()));
int[] location = new int[2];
tv.getLocationOnScreen(location);
Log.d("getlocationonscreen values :", Integer.toString(location[0])+" "+Integer.toString(location[1]));
}
#Override
protected void onStart() {
Log.d("getBottom in onStart :", Integer.toString(tv.getBottom()));
Log.d("gettop in onStart :", Integer.toString(tv.getTop()));
int[] location = new int[2];
tv.getLocationOnScreen(location);
Log.d("getlocationonscreen in onStart :", Integer.toString(location[0])+" "+Integer.toString(location[1]));
super.onStart();
}
Layout 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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="156dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
Again, I apologize for repeating the question. Thanks in advance.
You put the 'measuring' in the onWindowFocusChanged()-method.
As the documentation states:
This is the best indicator of whether this activity is visible to the user.
You could also put it in the onResume() which is the last step before the application is completely on screen and active, however:
Keep in mind that onResume is not the best indicator that your activity is visible to the user; a system window such as the keyguard may be in front. Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).
If the window/view has not yet been displayed there is no guarantee that it has its measurements, thus the previous method would be better.
I am trying to remove footer I've set using the same reference I used to set it up. However, nothing happens.
protected void onPostExecute(ArrayList<Recipe> result) {
int CHEF_ID = ChefsRecipeList.this.getIntent().getIntExtra("CHEF_ID", 0);
ListView recipeListView = (ListView)findViewById(android.R.id.list);
View footer = getLayoutInflater().inflate(R.layout.chef_recipe_list_footer, null);
if(!addToExisting){
RecipeManager.getInstance().setRecipeList(result);
View header = getLayoutInflater().inflate(R.layout.chef_recipe_list_header, null);
ImageView loadButton = (ImageView)footer.findViewById(R.id.loadmore);
loadButton.setOnClickListener( new OnClickListener() {
#Override
public void onClick(View v) {
int CHEF_ID = ChefsRecipeList.this.getIntent().getIntExtra("CHEF_ID", 0);
try {
Log.d("NXTLAOD", "http://api.foodnetworkasia.com/api/mobile/get_recipes?chefId="+ChefManager.getInstance().getChef(CHEF_ID).getId()+
"&format=xml&startIndex="+(RecipeManager.getInstance().getRecipeList().size()+1)+"&endIndex="+(RecipeManager.getInstance().getRecipeList().size()+24));
new XMLRecipesParser(true).execute(new URL[] { new URL("http://api.foodnetworkasia.com/api/mobile/get_recipes?chefId="+ChefManager.getInstance().getChef(CHEF_ID).getId()+
"&format=xml&startIndex="+RecipeManager.getInstance().getRecipeList().size()+"&endIndex="+(RecipeManager.getInstance().getRecipeList().size()+24)) } );
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
ImageView chefPhoto = (ImageView)header.findViewById(R.id.chef_photo);
chefPhoto.setImageBitmap(ImageURLLoader.LoadImageFromURL(ChefManager.getInstance().getChef(CHEF_ID).getLargeURL()));
TextView chefBio = (TextView)header.findViewById(R.id.chef_bio);
chefBio.setText(ChefManager.getInstance().getChef(CHEF_ID).getDescription());
recipeListView.addHeaderView(header);
recipeListView.addFooterView(footer);
recipeListView.setAdapter(new RecipeAdapter(ChefsRecipeList.this));
}else{
RecipeManager.getInstance().mergeLists(result);
RecipeAdapter wrapperAdapter=(RecipeAdapter) ((HeaderViewListAdapter)recipeListView.getAdapter()).getWrappedAdapter();
wrapperAdapter.notifyDataSetChanged();
}
if(totalRecipes == RecipeManager.getInstance().getRecipeList().size()){
recipeListView.removeFooterView(footer);
Log.d("FOODREM", "Footer Removed");
}
Log.d("ITCOUNT", totalRecipes+"-"+RecipeManager.getInstance().getRecipeList().size());
updateItemscount();
}
}
You might have to call listView1.setAdapter(adapter) to refresh the listview. If that doesn't work, another solution is to make the height of the footer view to 0px. This is a better solution if you are planning to use the footer view later on again.
You can also set the footer visibility for GONE. To do that, you need to wrap the content of your footer using a linearlayout, then you set the linearlayout visibility to GONE.
In the example bellow I set the visibility of LogoLinearLayout to GONE.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/LogoLinearLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/Logo"
android:src="#drawable/Logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/spacing3"
android:layout_marginBottom="#dimen/spacing3"
android:layout_gravity="center" />
</LinearLayout>
</LinearLayout>
I have seen this type of solution (setting the footer view's height to 0, or setting negative margins..) on many posts related to hiding the footer issue, and it does work, but with 2 issues:
- the list will not respect the transcriptMode="normal" anymore, in the sense that, if the last item is visible and a new item is added to the list, the list will not scroll to the newly added item;
- when keyboard is shown and list size changed, the list again will not show you the last item.
Can anyone tell me what's wrong with this implementation? All I want to do here is have two overlapping views that swap places when you tap the screen. Unless I'm just using it wrong, View.bringToFront() does nothing?
Below is all the code in my app. Note that I added padding to the 'backView' just to make sure the two were actually overlapping. Indeed I could see both on the screen. While tapping the top view does indeed trigger the onClick method, nothing visibly changes in response to the calls to bringToFront.
public class MainActivity extends Activity implements OnClickListener {
private ImageView frontView;
private ImageView backView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
frontView = (ImageView) findViewById(com.example.R.id.FrontView);
backView = (ImageView) findViewById(com.example.R.id.BackView);
frontView.setOnClickListener(this);
backView.setOnClickListener(this);
backView.setPadding(10,0,0,0);
}
private boolean flag;
public void onClick(View v) {
if (!flag) {
backView.bringToFront();
}
else {
frontView.bringToFront();
}
flag = !flag;
}
}
and the corresponding layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/FrontView"
android:src="#drawable/front"
/>
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/BackView"
android:src="#drawable/back"
/>
</RelativeLayout>
Maybe it's the layout I'm using? I'm not sure... I've tried FrameLayout and LinearLayout as well.
I would try swapping content views instead of ImageViews.
Put each imageView in a different layout and then it is easy:
public void onClick(View v) {
if (!flag) {
setContentView(R.layout.main_front);
frontView = (ImageView) findViewById(com.example.R.id.FrontView);
frontView.setOnClickListener(this);
}
else {
setContentView(R.layout.main_back);
backView = (ImageView) findViewById(com.example.R.id.BackView);
backView.setOnClickListener(this);
}
flag = !flag;
}
There are a couple of Components that you can use that do this for you.
ViewAnimator, ViewFlipper and ViewSwitcher. You can set the animations you require etc and they hand the rest.
here's one example.
http://www.androidpeople.com/android-viewflipper-example/
Given your example, do you have to call invalidate() on the parent after you've called bringToFront() ?