I have two different layouts, say layout_1.xml & layout_2.xml. Both layouts have same elements inside it, but layout_2.xml has an additional TextView.
Only one layout will be called according to my needs. I want to perform a check if the textView is available in the layout.
If the TextView is available, it should perform textView.setText(), else the other layout will be called.
Please refer the code below:
#Override
public void onBindViewHolder(SingleItemRowHolder holder, int i) {
SingleItemModel singleItem = itemsList.get(i);
holder.tvTitle.setText(singleItem.getName());
Picasso.with(mContext).load(singleItem.getUrl()).into(holder.itemImage);
if (holder.lblDescription.getVisibility() == View.VISIBLE){
holder.lblDescription.setText(singleItem.getDescription());
}
}
The TextView holder.lblDescription is in layout_2.xml, but is not present in layout_1.xml.
Therefore, layout_2.xml is running with ease, but when it calls layout_1.xml its giving me this error Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference.
I know, the check I am performing is wrong. So, I need help in this.
Thanks in advance!
Well you are getting a null pointer exception because lblDescription isn't bound to anything in layout_1.xml where it isn't present. So basically what you can do is you can check
if(hold.lblDescription != null){
holder.lblDescription.setText(singleItem.getDescription());
}
instead of
if (holder.lblDescription.getVisibility() == View.VISIBLE){
holder.lblDescription.setText(singleItem.getDescription());
}
/**
* check textview is present or not
*
* #param group : parent layout id
*/
public boolean isTextViewPresent(ViewGroup group)
{
int count = group.getChildCount();
View v;
for (int i = 0; i < count; i++)
{
v = group.getChildAt(i);
if (v instanceof TextView)
{
return true;
} else if (v instanceof ViewGroup)
isTextViewPresent((ViewGroup) v);
}
return false;
}
Related
Hello can anybody tell me why this code give me error and crash my app?
This happens only when 'reset((View) child);' is added at the end
What I want to do is when I click a Button with onClick:reset, It will apply a kind of reset to only Images and textviews inside a LinearLayout which has more types of childrens
public void reset(View v) {
LinearLayout items = (LinearLayout) findViewById(R.id.itemsToSearch);
for (int i = 0; i < items.getChildCount(); i++)
{
Object child = items.getChildAt(i);
Context context = getApplicationContext();
CharSequence text = child.toString();
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
if (child instanceof ImageView)
{
((ImageView) child).setVisibility(View.INVISIBLE);
}
else if (child instanceof TextView)
{
((TextView) child).setTextColor(Color.parseColor("#98868A"));
}
else if(child instanceof ViewGroup)
{
reset((View) child);
}
}
}
and the other question is that my app works with FragmentPagerAdapter, How can I do for example if I click a Button in Frag#1 it will change a text inside Frag#3 which is currently not shown?, For me it always crash, As I see it is because Frag#3 or whatever other frag which is off screen is not yet loaded on screen and because of that it doesnt fint the specified ID
Thank You
Your reset method is broken. You are not using the view that is passed as an argument to the method, you are always searching for the same LinearLayout. Your code should look like this:
public void reset(ViewGroup viewGroup) {
final int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = viewGroup.getChildAt(i);
if (child instanceof ImageView) {
((ImageView) child).setVisibility(View.INVISIBLE);
} else if (child instanceof TextView) {
((TextView) child).setTextColor(Color.parseColor("#98868A"));
} else if(child instanceof ViewGroup) {
// recursive call
reset((ViewGroup) child);
}
}
}
Regarding your other issue, only the current fragment and the ones to either side (within the offscreen page limit, which by default is 1) are actually loaded and in a state where you can manipulate their views. You will need to store some data somewhere and refer back to that data when the page you want (Fragment #3 in your example) is instantiated and you start loading data into it.
I have a custom adapter that renders two (2) checkboxes, a picture and the name of the client. All the information needed for the adapter is fetched from an ArratList that contains the Client class.
Every row needs to have both checkboxes checked (selected) for the client in order to process the purchase order, in case that a particular client has one checkbox checked-off and the other checkbox not, that raises a flag as MISMATCH. To make a valid order both checkboxes need to be checked-off.
We are implementing a button for verification, which will find any mismatch in the adapter and then hightlight the mismatches.
EDITION: After pressing the verificationBtn I am able to identify if any row has mismatch on checkboxes, for example, if checkbox1 was checked and checkbox2 not. that will mark the row as mismatch. I am using the position of my checkboxes based on clientList that is an arraylist of List clientList.
QUESTION: How can I get the position that the viewHolder has in order compare against the clientList position? Is there any way I can force the viewHolder to store the position and get it back and make the comparison with cli.getClient_number() ?
So far I have tested two different ways with no luck:
Method 1:
viewHolder.clientName.setBackgroundColor((Interger.parseInt(cli.getClient_number()) ) == position ? Color.GREEN : Color.TRANSPARENT);
Method 2
viewHolder.clientName.setBackgroundColor(Color.GREEN);
here the code that I am implementing.
// This goes in my main Client Activity
Button verificationBtn = (Button) findViewById(R.id.verificationBtn);
verificationBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
buffer.setLength(0);
mismatchTv.setText("");
for (Client cli : clientList) {
if (cli.isCheckboxOneSelected() != cli.isCheckboxTwoSelected()) {
//We had defined above the following buffer = new StringBuffer();
buffer.append((ah.parseInt(cli.getClient_number(), 0) - 1) + ", ");
cli.setMismatch(true);
//We are passing here the ID that correspond to the client mismatch
list_adapter.setBackgroundColor(Integer.parseInt(cli.getClient_number()) - 1);
setListAdapter(list_adapter);
Log.w("cli.getClient_number() ", String.valueOf(Integer.parseInt(cli.getClient_number()) - 1));
}
}
// We display any mismatch on a TextView on top of the screen
if (buffer.length() != 0) {
//This is a TextView on top of the screen
mismatchTv.setText("Error en Client(s) "
+ buffer.toString());
}
// This goes inside of the ClientArrayAdapter
public void setBackgroundColor(int position) {
Log.w("inside of setBackgroundColor method", "True");
switchIndex = 1;
positionFetched = position;
}
// This goes inside of the ClientArrayAdapter
// and inside the body of public View getView(int position, View convertView, ViewGroup parent) {
switch (switchIndex) {
case 1:
viewHolder.cbone
.setButtonDrawable(R.drawable.btn_checkbox_selector);
viewHolder.cbtwo
.setButtonDrawable(R.drawable.btn_checkbox_selector);
Log.w("switch 1 was called ", "True");
for (Client cli : clientList) {
if (cli.isCheckboxOneSelected() != cli.isCheckboxTwoSelected()) {
Client cli = getItem(positionFetched);
if (cli.isMismatch()) {
cli.setColor(Color.BLACK);
Log.e("if (cli.isMismatch()) ", "");
//HERE WE ARE TRYING TO HIGHLIGHT THE ROW WITH MISMATCH
//WHY THIS LINE DOES NOT WORK?
//THE ISSUE THAT I AM GETTING IS THAT I CANNOT CONTROL WHAT ROW TO AFFECT
//IN THE VIEW HOLDER
viewHolder.clientName.setBackgroundColor(Color.GREEN);
}
}
}
break;
default:
viewHolder.cbone.setButtonDrawable(R.drawable.disabled_cb);
viewHolder.cbtwo.setButtonDrawable(R.drawable.disabled_cb);
break;
}
// This goes inside of the ClientArrayAdapter
static class ViewHolder {
public TextView clientName;
public TextView clientNumber;
public ImageView imageView;
public CheckBox cbtwo;
public CheckBox cbone;
public int position;
}
After three days trying to figure out what's wrong with this code, I finally found the solution moving the Method #1 just at the very end of the getView method. :-)
I have a error function that takes View as an input, and shows error by changing its background to red while there is any problem with view's value as follows -
public static void error(View v) {
v.setBackgroundResource(android.R.color.holo_red_light);
}
I am using this function in another function where I am using it this way -
public static void nonEmptyNonZero(View v) {
String check = "";
check = ((TextView) v).getText().toString();
if ((check.equals(null)) || check.equals("0") || check.equals("")) {
error(v);
}
}
my issue is, that v could be anything (TextView, EditText). So how to identify what is the type of the view. So that I could use proper casting while getting its value using -
check = ((TextView) v).getText().toString();
PS - I have used instanceOf already, I am not sure how casting of a View works.
Like your Views in Object List
List<Object> objectViews=new ArrayList();
views
EditText txtEditText=new EditText();
TextView txtTextView=new TextView();
objectViews.add(txtEditText);
objectViews.add(txtTextView);
traverse to find object (view)
Object view=new Object();
for(int i=0;i<objectViews.size;i++)
{
view.get(i);
if(view instanceof EditText)
{
Log.e("EditText","value="((EditText) view).getText());
}
else if(view instanceof TextView)
{
Log.e("TextView","value="((TextView) view).getText());
}
}
can anyone help me with coding a method to get all EditTexts in a view? I would like to implement the solution htafoya posted here:
How to hide soft keyboard on android after clicking outside EditText?
Unfortunately the getFields() method is missing and htafoya did not answer our request to share his getFields() method.
EDIT
MByD pointed me to an error, thus making my answer almost identical to that of blackbelt. I have edited mine to the correct approach.
You could do a for-each loop and then check if each view is of the type EditText:
ArrayList<EditText> myEditTextList = new ArrayList<EditText>();
for( int i = 0; i < myLayout.getChildCount(); i++ )
if( myLayout.getChildAt( i ) instanceof EditText )
myEditTextList.add( (EditText) myLayout.getChildAt( i ) );
You could also, instead of having a list of EditTexts, have a list of ID's and then just add the id of the child to the list: myIdList.add( child.getId() );
To access your layout you need to get a reference for it. This means you need to provide an ID for your layout in your XML:
<LinearLayout android:id="#+id/myLinearLayout" >
//Here is where your EditTexts would be declared
</LinearLayout>
Then when you inflate the layout in your activity you just make sure to save a reference to it:
LinearLayout myLinearLayout;
public void onCreate( Bundle savedInstanceState ) {
super( savedInstanceState );
setContentView( R.layout.myLayoutWithEditTexts );
...
myLinearLayout = (LinearLayout) findViewById( R.id.myLinearLayout );
}
You then have a reference to your the holder of your EditTexts within the activity.
Here's a method I wrote to recursively check all EditText children of a ViewGroup, handy for a long sign-up form I had to do and probably more maintainable.
private EditText traverseEditTexts(ViewGroup v)
{
EditText invalid = null;
for (int i = 0; i < v.getChildCount(); i++)
{
Object child = v.getChildAt(i);
if (child instanceof EditText)
{
EditText e = (EditText)child;
if(e.getText().length() == 0) // Whatever logic here to determine if valid.
{
return e; // Stops at first invalid one. But you could add this to a list.
}
}
else if(child instanceof ViewGroup)
{
invalid = traverseEditTexts((ViewGroup)child); // Recursive call.
if(invalid != null)
{
break;
}
}
}
return invalid;
}
private boolean validateFields()
{
EditText emptyText = traverseEditTexts(mainLayout);
if(emptyText != null)
{
Toast.makeText(this, "This field cannot be empty.", Toast.LENGTH_SHORT).show();
emptyText.requestFocus(); // Scrolls view to this field.
}
return emptyText == null;
}
You can do it by calling View#getFocusables, which will return an arraylist of all focusable views in a View.
Then you can either check if they are EditTexts, with (instanceof) or act on all of them.
This Methods walks recursively through all ViewGroups and collects their TextViews. I use this to assign a new Color to all TextViews (even those embedded in predefined Widgets like Switch etc that make use of TextViews)
private HashSet<TextView> getTextViews(ViewGroup root){
HashSet<TextView> views=new HashSet<>();
for(int i=0;i<root.getChildCount();i++){
View v=root.getChildAt(i);
if(v instanceof TextView){
views.add((TextView)v);
}else if(v instanceof ViewGroup){
views.addAll(getTextViews((ViewGroup)v));
}
}
return views;
}
Get all Edit Text in any type of layout.
public List<EditText> getAllEditTexts(ViewGroup layout){
List<EditText> views = new ArrayList<>();
for(int i =0; i< layout.getChildCount(); i++){
View v =layout.getChildAt(i);
if(v instanceof EditText){
views.add((EditText)v);
}
}
return views;
}
I have a view with radios, inputs and a button and when I click it, I want to check that all inputs contain information. How can I iterate through the view's elements in the activity and check if every textview meets the aforementioned requirement ? Thanks.
I've done something similar in some code I don't have with me at the moment, but from memory it should be something like this (assuming a parent view LinearLayout with an id of "layout"):
LinearLayout layout = (LinearLayout)findViewById(R.id.layout);
boolean success = formIsValid(layout);
public boolean formIsValid(LinearLayout layout) {
for (int i = 0; i < layout.getChildCount(); i++) {
View v = layout.getChildAt(i);
if (v instanceof EditText) {
//validate your EditText here
} else if (v instanceof RadioButton) {
//validate RadioButton
} //etc. If it fails anywhere, just return false.
}
return true;
}
To apply the method by kcoppock recursively, you can change it to this:
private void loopViews(ViewGroup view) {
for (int i = 0; i < view.getChildCount(); i++) {
View v = view.getChildAt(i);
if (v instanceof EditText) {
// Do something
} else if (v instanceof ViewGroup) {
this.loopViews((ViewGroup) v);
}
}
}
If you are writing in Kotlin, Android Jetpack's Kotlin extensions (KTX) provide extension functions for iterating over a ViewGroup's children.
myViewGroup.forEach { ... }
myViewGroup.forEachIndexed { index, view -> ... }
Just add the dependency to your app. Check the link above to get the most up-to-date version.
implementation "androidx.core:core-ktx:1.2.0"
These extensions contains hoards of useful functions otherwise chalked up as boilerplate. Worth checking out now to save time in the future!
Your onClickListener supplies the View v object; use View rV = v.getRootView() to position yourself on the form. Then use rV.findViewWithTag( ... ) or rV.findViewByID(R.id. ... ) to locate your form elements.