I have created an app in which I am fetching data from server. So, I have used JSON parsing in my code. I am successfully parsed my JSON from server. Now I want to set buttons in layout according to their visibility getting from JSON response.
That is if visibility true then button should visible and if false button should disable. It works but if some button has visibility false then there is a space in layout. So how to set in layout dynamically that all visible buttons show in line.
I have created three linear layouts each contains three buttons.Now if json response says visibility false for some button I set visibility to off for that button.
if (Menuname.equals("StudentDailyDiary")) {
studentdiary.setVisibility(View.VISIBLE);
moreOptionLayout.setVisibility(View.VISIBLE);
hrview.setVisibility(View.VISIBLE);
rlleftview.setVisibility(View.VISIBLE);
rlrightview.setVisibility(View.VISIBLE);
}
if (Menuname.equals("BookSearch")) {
studlibrary.setVisibility(View.VISIBLE);
moreOptionLayout.setVisibility(View.VISIBLE);
hrview.setVisibility(View.VISIBLE);
rlleftview.setVisibility(View.VISIBLE);
rlrightview.setVisibility(View.VISIBLE);
}
Say in first layout three buttons are there from which second button has visibility false then on position of second button third button should be placed there should be no blank space for buttons in all layout.That is if third button has visibility false then first button of second layout should set on position of third button.
I think that the correct ViewGroup to use is the GridLayout.
Here a simple example:
activity_main.xml
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="80dp"
android:gravity="center"
android:numColumns="3"
android:stretchMode="columnWidth" />
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val numbers = arrayOf("BUTTON1", "BUTTON2", "BUTTON4", "BUTTON5", "BUTTON6")
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, numbers)
gridView.adapter = adapter
gridView.onItemClickListener = AdapterView.OnItemClickListener {
parent, v, position, id ->
Toast.makeText(applicationContext, (v as TextView).text, Toast.LENGTH_SHORT).show()
}
}
}
This example uses String but you can make an Adapter of whatever you want. Now after you JSON response just fill your array and set it to the adapter.
Hope it helps
there are three options for elements visibility,
View.VISIBLE
View.INVISIBLE
View.GONE
use View.GONE for elements that you don't want to show.
the different between
View.INVISIBLE
and
View.GONE
is that View.GONE take no space and you should use view.GONE
You have two option to do this
1:-
View.VISIBLE //Visible the view which is acquire its space
View.INVISIBLE //Invisible the view and it acquire the space
View.GONE //visibility Gone of its view and also not acquire view space
2:-
you can use RecyclerView and pass the model to adapter and then show buttons according to its model.
Set your buttons Visibility to Gone in your layout XML
So they don't left any blank space while their Visibility are INVISIBLE
<Button
android:id="#+id/btn_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"/>
Related
How to completely make a view off to focus state? I am adding these parameters in the xml but with the keyboard still able to focus the view.
What I have tried till now;
android:focusable="false"
android:focusableInTouchMode="false"
For instance I got 3 views. I want to set View2 unfocusable so if I use keyboard and focus View1 after switch to another one View3 will be in focus and View2 will be ignored..
How can I do that? Any solutions?
Assuming that you dont want the other views to be used when you are using one .
In the onClickListener of each View , you can set the other two to be unusable .This function could do the trick .
//Kotlin Code
private fun setImageViewStatus(view: View, value: Boolean) {
view.apply {
isEnabled = value
isClickable = value
}
}
You can replace view with anything of your choice .
In your XML for View1 try adding a property for nextFocusDown. For example if the ID of View3 is View3 add the following to the XML for View1:
android:nextFocusDown="#+id/View3"
I`ve a recycler with custom CircleView and some part in right side. I need to change right side background color for each item programmatically. Every item in list must have its own color.
Item`s right side code:
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/card_rarity_info"
android:layout_width="0dp"
android:layout_height="78dp"
android:background="#drawable/shape_rarity"
app:layout_constraintBottom_toBottomOf="#id/circle_rarity_color"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/circle_rarity_color"
app:layout_constraintTop_toTopOf="#id/circle_rarity_color"
tools:backgroundTint="#color/colorPrimary">
<TextView ... />
<TextView ... />
</androidx.constraintlayout.widget.ConstraintLayout>
Setting backgroundTint in recycler view adapter:
override fun onBindViewHolder(holder: RaritiesViewHolder, position: Int) {
...
rarities[position].color?.let {
holder.cardRarityInfo.background.setTint(Color.parseColor("#$it"))
}
}
But result incorrect! It set up the last item color for every item in list
Just need to use mutate() for drawable.
That's why every item have same color:
By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification.
When I use mutate() for recycler items in adapter, it produce states for every single item in list.
Usage:
override fun onBindViewHolder(holder: SomeViewHolder, position: Int) {
rarities[position].color?.let {
holder.circleView.setCircleColor(it) // custom view fun which take HEX parse it and invalidate
holder.cardInfo.background.run {
mutate()
setTint(Color.parseColor("#$it"))
}
}
<...>
}
For more information article and documentation
An activity in our Android application features a spinner, the selected value of which affects which other views are to be displayed in the activity (these views are inputs for sub-parameters of the spinner parameter, and so are spinner value specific).
The contents of the activity (below the top-most spinner) should change dynamically upon spinner selection and is visualized with this very quick mockup:
Initially, we had the sub-parameters in their own linear layouts in the activity xml, and upon spinner selection change, hid all the irrelevant sub-parameter layouts, but this seems a fairly rotten approach, and also severely undermines the extensibility of the activity (in terms of adding new top spinner box options and sub-parameters).
We've also considered generating the layout completely in code with declarations of the types of inputs needed (with some encapsulated layout generator based on these declarations) for each parameter, but this seemed a bit of an over-complication, and we'd really prefer to define the sub-parameter layouts in xml.
How should we approach this?
Would this be an appropriate scenario for using fragments? (would using fragments involve hiding and showing them just as awfully as using the sub-parameter linear layouts?
Thanks!
For anyone out there seeking a solution:
We ended up having an empty 'container' view (a linear layout) within our activity's xml, which will store the sub-menus...
<LinearLayout
android:id="#+id/algorithm_layout_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</LinearLayout>
and seperate xml layout files for each of the sub-menus (eg; the empty negative sub-menu...)
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
tools:context="PACKAGE.ACTIVITY"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
installing an onItemSelectedListener (well actually, having our activity implement it) and upon the selected spinner item changing, adjust the displayed sub-menu by clearing the container, and adding the sub-menus corresponding layout (inflated to a view) to the container...
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// get the current spinner value
String choice = parent.getSelectedItem().toString();
// get and clear our sub-menu container
LinearLayout container = (LinearLayout) findViewById(R.id.algorithm_layout_container);
container.removeAllViews();
// determine which sub-menu layout to set by the spinner option
// (we're exploiting the strings.xml string identifier for our own identification)
int layout;
if (choice.equals(getString(R.string.halftone_algorithm_choice))) {
layout = R.layout.algorithm_halftone;;
}
else if (choice.equals(getString(R.string.negative_algorithm_choice))) {
layout = R.layout.algorithm_negative;
}
else if (choice.equals(getString(R.string.gaussian_algorithm_choice))) {
layout = R.layout.algorithm_gaussian;
}
else if (choice.equals(getString(R.string.dithering_algorithm_choice))) {
layout = R.layout.algorithm_dithering;
} else {
// only reached via a dev bug: you've got an unexpected spinner value selected
// we handle this with an alert, then switch to another (default) spinner value
}
// inflate the determined layout to a view, and add it to our container
container.addView(LayoutInflater.from(this).inflate(layout, null, false));
}
I want to make an application that show lyric of sound with music,
I put lyrics in a custom made listview with layout below ( layout for row's ), and time of that lyric in text separated with comma,
then, I want to scroll with media.
This is my custom layout for rows:
<TextView
android:id="#+id/custom_text_arabic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:gravity="center"
android:lineSpacingExtra="15dp"
android:textSize="20sp" />
<TextView
android:id="#+id/custom_text_persian"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:lineSpacingExtra="10dp"
android:textColor="#999999"
android:textSize="12sp" />
</LinearLayout>
and I have an adapter for this custom row layout in list view,
I have a music file that plays with MediaPlayer and I get current position of sound and check that in an array of time to find the position of row in list view, then I scroll to that row in a listview, along side this things, I want that row background change to black!
So, I get that row with this code and change it!
// cAdapter is the name of my BaseAdapter and whereIsMe is current child of listview
// that i want to manipulate it
View mVi = cAdapter.getView(whereIsMe-1, null, lv);
TextView persian = (TextView) mVi.findViewById(R.id.custom_text_persian);
// this toast works great!
Toast.makeText(getApplicationContext(),persian.getText(), Toast.LENGTH_LONG).show();
// this part of code is not working!
persian.setBackgroundColor( Color.BLACK );
the problem is:
I can Toast Text in a TextView perfectly! But I can't change that TextView Background or any other manipulation! why and how can I fix that?
Calling getView doesn't return the actual child of the ListView. There are two options, you can call getChild for the ListViewand update the background color or call notifyDataSetChanged and set the background color in your adapter getView method.
The getView method of the adapter is not meant to be used as you are using it.
Read some tutorials on creating a custom adapter for a listView. Then you can do whatever you want.
Here is a good read on custom adapters;
http://www.vogella.com/tutorials/AndroidListView/article.html
For getting the view you want from outside the adapter use something like this:
View view;
int nFirstPos = lv_data.getFirstVisiblePosition();
int nWantedPos = invalidaEste - nFirstPos;
if ((nWantedPos >= 0) && (nWantedPos <= lv_data.getChildCount())
{
view = lv_data.getChildAt(nWantedPos);
if (view == null)
return;
// else we have the view we want
}
Sometimes listView.getChildAt(int index) returns NULL (Android)
This happens because getView is called internally to create a view. by what you are doing you are actually creating a new view which is not added to any screen/layout so any changes you do wont be reflected on the UI
I'm having some problems when trying to remove the header from a listView. At first I use addHeaderView() to add it, but when I change to another layout I want it to disappear but removeHeaderView() doesn't work...
I also tried setting visibility to GONE and it doesn't disappear...
What can I do?
Thanks in advance
Try the approach mentioned below..
Android ListView#addHeaderView and ListView#addFooterView methods are strange: you have to add the header and footer Views before you set the ListView's adapter so the ListView can take the headers and footers into consideration -- you get an exception otherwise. Here we add a ProgressBar (spinner) as the headerView:
// spinner is a ProgressBar
listView.addHeaderView(spinner);
We'd like to be able to show and hide that spinner at will, but removing it outright is dangerous because we'd never be able to add it again without destroying the ListView -- remember, we can't addHeaderView after we've it's adapter:
listView.removeHeaderView(spinner); //dangerous!
So let's hide it! Turns out that's hard, too. Just hiding the spinner view itself results in an empty, but still visible, header area.
Now try to hide the spinner:
spinner.setVisibility(View.GONE);
Result: header area still visible with an ugly space:
The solution is to put the progress bar in a LinearLayout that wraps it's content, and hiding the content. That way the wrapping LinearLayout will collapse when its content is hidden, resulting in a headerView that is technically still present, but 0dip high:
<LinearLayout
xmlns:a="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- simplified -->
<ProgressBar
android:id="#+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Then, set the layout as the header:
spinnerLayout = getLayoutInflater().inflate(R.layout.header_view_spinner, null);
listView.addHeaderView(spinnerLayout);
And when we need to hide it, hide the layout's content, not the layout:
spinnerLayout.findViewById(R.id.spinner).setVisibility(View.GONE);
Now the header disappears from view. No more ugly space at the top!
Most people don't like to use AddHeaderView, however I sometimes found it very convenient, to avoid modifying complex adapters, or if the headers are not very related to them.
With this easy trick you will be able to seamlessly remove/add headers:
I add an empty LinearLayout with orientation vertical, and height wrap_content, as the only Header View (let mListView be the target listView):
LinearLayout mCustomHeaders=new LinearLayout(context);
mCustomHeaders.setOrientation(LinearLayout.VERTICAL);
mListView.addHeaderView(mCustomHeaders);
mListView.setAdapter (.......)
Thenafter, I can add random stuff, anywhere, to the list as header, even when the list is full:
mCustomHeaders.add(myHeaderView1);
mCustomHeaders.add(myHeaderView2);
mCustomHeaders.add(myHeaderView3);
You can also delete all headers, anytime:
mCustomHeaders.removeAllViews(); // will erase all headers
You get the idea .... Hope it helps !
The problem is that you are always creating a new object when you do:
View headerView = someView
So the new view is not the same as the view already added as listView header, try this:
View headerView = inflater.inflate(R.layout.adapter_datatable_saleitem_header, null, false);
headerView.setTag(this.getClass().getSimpleName() + "header");
if (listView.getHeaderViewsCount() > 0) {
View oldView = listView.findViewWithTag(this.getClass().getSimpleName() + "header");
if (oldView != null) {
listView.removeHeaderView(oldView);
}
}
You can check if header count > 0 then remove the header and add it again.
its works fine for me.
View _headerView;
private void function HandleHeaderView(){
if(listView.getHeaderViewsCount() > 0)
{
listView.removeHeaderView(_headerView);
}
/* Add list view header */
_headerView = GetHeaderView();
listView.addHeaderView(_headerView);
}
private View GetHeaderView()
{
View header = getLayoutInflater().inflate(R.layout.header_layout, null);
// TODO: ...
return header
}
Where drawerLogoView is my headerview, here's what I do:
drawerLogoView = mInflater.inflate(R.layout.navigation_drawer_custom_layout, null);
mDrawerList.addHeaderView(drawerLogoView,null,false);
LinearLayout layOut = ((LinearLayout)drawerLogoView.findViewById(R.id.NavProfilePreviewLayout));
layOut.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 0));
That way, it becomes invisible :D
To show it back, you can use this:
LinearLayout layOut = ((LinearLayout)drawerLogoView.findViewById(R.id.NavProfilePreviewLayout));
layOut.setLayoutParams(newRelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
If you are using addHeaderView(), you can't delete your header after that.
So, don't use addHeaderView(). Rather, create your own adapter that
blends your main roster of Views with your header. While my
MergeAdapter will not handle your specific case, you can use it to see
the concept of blending multiple row sources:
https://github.com/commonsguy/cwac-merge
I encountered this problem in a slightly disguised scenario: the ListView I was dealing with came from PreferenceFragment, and the header represents a PreferenceCategory. So, my freedom of setting up the ListView was severely limited. But there were two approaches (partly inspired by other answers on this page). One was to add a custom layout to my PreferenceCategory (using a class that extends android.preference.PreferenceCategory, see Custom PreferenceCategory Headings). But I found an easier workaround: for the first Preference in this PreferenceCategory, I override onCreateView():
#Override public View onCreateView(ViewGroup parent) {
parent.setTop(-parent.getChildAt(0).getTop());
return super.onCreateView(parent);
}