In my fragment class, I add a child view element programmatically to my layout conditionally :
LinearLayout child = (LinearLayout) inflater.inflate(R.layout.child_view, null);
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,100);
container.addView(child, params);
Since the above code will be run conditionally, so, at some point, I would like to check if the child view has added or not, how to make this checking programmatically?
If you creating view via inflater, you can check his parent
if(view.getParent() != null) {...}
I think you can simply use
findViewById(your_view_id)
method: If its result is null the view does not exists, otherwise the view is present
Sorry for late reply but you may try this alternative:
use container.getChildCount(); before adding and after adding a view. Like :
int x = container.getChildCount();
container.addView(child, params);
int y = container.getChildCount();
if(y > x)
Toast.makeText(context, "View Successfully Added!", Toas.LENGTH_SHORT).show();
Or if you have a view instance to find, you could:
if (container.indexOfChild(childView) == -1) {
// Add child to container.
}
With AndroidX you can use ViewGroup.contains(view: View): Boolean extension function.
I cannot write a comment so I write it here as a solution:
From API level 19 you can call isAttachedToWindow() which doesn't help a lot, but if you are aiming API 19 or higher, then this should work by the documentation.
maybe you can try this
child.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
child.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// add to parent
}
});
or this one
child.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
#Override
public void onViewAttachedToWindow(View v) {
}
#Override
public void onViewDetachedFromWindow(View v) {
}
});
Related
In my app, I need to show and hide widgets like button and textview at a certain time.
and how I am doing is as the following:
private void hideviews() {
image.setVisibility(View.GONE); ///ImageView
title1.setVisibility(View.GONE);///TextView
title2.setVisibility(View.GONE);///TextView
title3.setVisibility(View.GONE);///TextView
title4.setVisibility(View.GONE);///TextView
title5.setVisibility(View.GONE);///TextView
}
private void showviews() {
image.setVisibility(View.VISIBLE);
title1.setVisibility(View.VISIBLE);///TextView
title2.setVisibility(View.VISIBLE);///TextView
title3.setVisibility(View.VISIBLE);///TextView
title4.setVisibility(View.VISIBLE);///TextView
title5.setVisibility(View.VISIBLE);///TextView
}
I don't think this is the correct way to do this.
Because I don't know how many widgets there will be.
Any guidance on how to correctly show widgets is really appreciated.
Get the reference to root layout, iterate through the childs, check if the view at certain index is instance of EditText(or View that you dont need to hide), if not hide it
RelativeLayout root = findViewById(R.id.root)
for(i=0,i<root.getChildCount()-1,i++){
if(! (root.getChildAt(i) instance of EditText)){
root.getChildAt(i).setVisibility(View.GONE)
}
}
Since you don't know how many testviews will be attached, then I believe that the best approach will be to:
get the reference of the parent view group (that contains all the
textviews),
loop through all the childs using getChildAt,
verify whether the object is an instance of TextView/ImageView and if so set its visibility according to your logic
Instead of hiding every widget separately hide the root layout.
RelativeLayout rootLayout;
rootLayout= (RelativeLayout) findViewById(R.id.root_layout);
and use something like this to control the visibility.
public void setLayoutInvisible() {
if (rootLayout.getVisibility() == View.VISIBLE) {
rootLayout.setVisibility(View.GONE);
}
}
public void setLayoutVisible() {
if (rootLayout.getVisibility() == View.GONE) {
rootLayout.setVisibility(View.VISIBLE);
}
}
Make an array of all the views that you want to show/hide:
View[] views = {image, title1, title2, title3, title4, title5};
and then use this to hide them:
for (View view : views) {
view.setVisibility(View.GONE);
}
and use this to show them:
for (View view : views) {
view.setVisibility(View.VISIBLE);
}
although you can combine the 2 code parts in a single procedure:
void fixViews(int state) {
for (View view : views) {
view.setVisibility(state);
}
}
and call it:
fixViews(View.GONE); or fixViews(View.VISIBLE);
I am working on an app using geolocation and I want to set a layout VISIBLE when close to a point and GONE when too far from the point.
This is my xml :
<LinearLayout
android:visibility="gone"
android:id="#+id/slidePane"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
Then I use the ID in the activity as usual :
declare it in the class attribute :
private LinearLayout slidepane;
set it in the onCreate() method :
slidepane = (LinearLayout) findViewById(R.id.slidePane);
And then I try to update it in onLocationChanged() method as follows :
if (InterestPoint.CalculationByDistance(location, new LatLng(47.247801, -1.551883)) < 0.03) {
Toast.makeText(MainActivity.mContext, "InterestPoint close", Toast.LENGTH_SHORT).show();
slidepane.setVisibility(View.VISIBLE);
} else {
slidepane.setVisibility(View.GONE);
}
So the condition is correct since the Toast appears but the layout does not become visible, why?
Thank you.
EDIT : I am using https://github.com/umano/AndroidSlidingUpPanel and try to set the visibility of the second child (the sliding panel). I didn't see anything in the documentation about visibility. I can still access the children of the LinearLayout but not the container itself (and especialy the visibility).
Replace this:
slidepane.setVisibility(View.VISIBLE);
with this:
runOnUiThread(new Runnable() {
#Override
public void run() {
slidepane.setVisibility(View.VISIBLE);
}
});
Make sure you set the visibility of view at the time of initialization.
#Override
protected void onCreate(Bundle savedInstanceState) {
........
slidepane = (LinearLayout) findViewById(R.id.slidePane);
slidepane.setVisibility(View.GONE);
.......
//onLocationChanged() add ->
if (InterestPoint.CalculationByDistance(location, new LatLng(47.247801, -1.551883)) < 0.03) {
Toast.makeText(MainActivity.mContext, "InterestPoint close", Toast.LENGTH_SHORT).show();
slidepane.setVisibility(View.VISIBLE);
} else {
slidepane.setVisibility(View.GONE);
}
I use Glide library inner custom adapter view in my apps. But I have Error :
"You must not call setTag() on a view Glide is targeting"
This part of my code :
#Override
public View getView(int position, View view, ViewGroup container) {
ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = holder.imageView = new ImageView(context);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.imageView.setAdjustViewBounds(true);
LinearLayout.LayoutParams vp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
holder.imageView .setLayoutParams(vp);
holder.imageView .setScaleType(ImageView.ScaleType.CENTER_CROP);
String var_news_article_images = imageIdList.get(getPosition(position));
Glide.with(context)
.load(var_news_article_images)
.placeholder(R.drawable.placeholder)
.into(holder.imageView);
return view;
}
so how to fix it ?
The key is ViewTarget.setTagId; setting it will free up the default setTag on the ImageView so you can use it as root in the item layout.
It was introduced in Glide 3.6.0 in issue #370.
In your manifest add this:
<application
android:name=".App"
Then create an application context class:
public class App extends Application {
#Override public void onCreate() {
super.onCreate();
ViewTarget.setTagId(R.id.glide_tag);
}
}
Add the following as contents for src/main/values/ids.xml:
<resources>
<item type="id" name="glide_tag" />
</resources>
(or just add the above <item ... /> into any resources xml in values)
Update: ViewTarget was deprecated since 4.8.0. If you're using into(ImageView), you'll still have to call the deprecated class's method, because the built-in *ViewTarget classes still extend the old class.
If you use a custom ViewTarget, migrate to CustomViewTarget as the replacement. This will remove the need for setting any tag ID, because the default behaviour for CustomViewTarget is using a Glide-specific ID, so it shouldn't clash with any setTag calls.
If you want to customise the ID anyway, you can use useTagId on your custom target.
Glide use setTag(Object) method internally. So remove all calls of setTag(Object) from your target view. ie ImageView
If you really required to use setTag method on your view, you can use setTag(int,Object) method instead.
From what I've found from Googling, seems like Glide and ViewHolder don't get along too well. I tried Picasso instead. Problem solved instantly.
You can also try the solution from TWiStErRob, but make sure you're using Glide 3.6.0 or higher. It did not recognize setTagId(int) on 3.5.2
ImageView mImageAds = (ImageView) findViewById(R.id.iv_img);
mImageAds.setTag(R.id.iv_img, i); // "i" means some integer value
Glide.with(getActivity()).load(urlPath)
.placeholder(R.drawable.ads_banner)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(mImageAds);
mImageAds.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if(mImageAds.getTag() != null) {
int position = (Integer) view.getTag(R.id.iv_img);
//code here what would you like to do.
}
}
});
See also : https://androidhiker.blogspot.com/2015/10/how-to-resolve-glide-settag-issue.html
I had the same issue, after removing the following
android:tag="xx"
from the image on my xml layout, that issue was gone
If you have freedom to use other library, use, else
you can use setTag(int, Object), but if you can't do above then wrap ImageView in a basic LinearLayout > setTag() on LinearLayout > setOnClickListener on LinearLayout.
Something like :
LinearLayout imgViewLinearLayout = new LinearLayout(context);
imgViewLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
imgViewLinearLayout.setId(R.id.dummy_image_layout);
imgViewLinearLayout.setOnClickListener(this);
ImageView imageView = new ImageView(inflater.getContext());
imageView.setPadding(0,15,20,0);
imageView.setId(R.id.imageview_for_glide);
imgViewLinearLayout.setTag("Image VIEWTAG");
imgViewLinearLayout.addView(imageView)
Override onClick and :
#Override
public void onClick(View v) {
if(v.getId() == R.id.dummy_image_layout){
//Do what you wanna wanted to do on click of ImageView
}
}
Hope this helps.
As written by Thu Thu, you can simply reference an id of any existing View. For instance, suppose you want to set tag to an ImageView:
image_view.setTag(R.id.image_view, 100)
if (image_view.getTag(R.id.image_view) == 100) ...
Use view.setTage(int, object); and view.getTag(int);
I have 4 LinearLayouts in a RelativeLayout and I am also using an ImageView. When the ImageView is displayed I want to disable the 4 LinearLayouts and their contents. Each LinearLayout contains 4 buttons. Shown below is my function to disable and enable these layouts. Can someone help me understand why this isn't working?
private void disablelayout(final LinearLayout l1,final LinearLayout l2,final LinearLayout l3,final LinearLayout l4)
{
l1.setEnabled(false);
l2.setEnabled(false);
l3.setEnabled(false);
l4.setEnabled(false);
}
private void enablelayout(final LinearLayout l1,final LinearLayout l2,final LinearLayout l3,final LinearLayout l4)
{
l1.postDelayed(new Runnable(){
#Override
public void run() {
l1.setEnabled(true);
l2.setEnabled(true);
l3.setEnabled(true);
l4.setEnabled(true);
}
}, 3000);
}
private void enableDisableView(View view, boolean enabled) {
view.setEnabled(enabled);
if ( view instanceof ViewGroup ) {
ViewGroup group = (ViewGroup)view;
for ( int idx = 0 ; idx < group.getChildCount() ; idx++ ) {
enableDisableView(group.getChildAt(idx), enabled);
}
}
}
Use setVisibility() to either INVISIBLE or GONE.
Use like this:
l1.setVisibility(View.GONE);
l2.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
Use can use this for hide the whole layout
l1.setVisibility(View.GONE);
l2.setVisibility(View.GONE);
l3.setVisibility(View.GONE);
l4.setVisibility(View.GONE);
whenever you want to display particular layout then you can
l1.setVisibility(View.VISIBLE);
Set "Clickable" property for all items to false. The method is setClickable(boolean).After that no one could click it. Also you could look into this question: How to disable an Android button
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.