I'm trying to make a set of views (that include several textviews and buttons - all in different parent layouts, but in the same activity) invisible if a particular condition is evaluated to false.
The conventional way to do that would be:
findViewById(R.id.myview).setVisibility(View.INVISIBLE);
My question is, will I have to do this for all the views one by one that I want to be invisible, And then toggle them back when I want them visible?
Or, is there a way to avoid the code-repetition?
If the Views are in different parents , you can't do it directly, but you can implement a method to change the visibility of a bunch of Views if you want to keep your code clean:
List<View> relatedViews = new ArrayList<>();
// ...
relatedViews.add(view1);
relatedViews.add(view2);
relatedViews.add(view3);
// ...
changeVisibility(relatedViews, View.INVISIBLE);
// ...
private void changeVisibility(List<View> views, int visibility) {
for (View view : views) {
view.setVisibility(visibility);
}
}
As a side note, you may want to change the visibility to View.GONE instead of View.INVISIBLE so it doesn't take any space in the layout.
you can use something like this. It's not the most elegant solution but works.
The idea is give to each view that you want to hide a same content description, because in the same layout you can not use same id for multiple view. With the same content description you can find all views in your layout and hide them.
That's an example considering the first layout as Linear. You can change obviously ;)
public class TestActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
LinearLayout rootLayout = (LinearLayout)findViewById(R.id.rootLayout);
int childcount = rootLayout.getChildCount();
for (int i=0; i < childcount; i++){
View v = rootLayout.getChildAt(i);
if(v.getContentDescription() != null && v.getContentDescription().equals("invisibleView")){
v.setVisibility(View.INVISIBLE);
//I suggest you to use GONE instead of INVISIBLE to remove the space of the view
}
}
}
}
in your xml give to the object that you want to hide this property
android:contentDescription="invisibleView"
Use varargs method for show or hide multiple views.
for example if you have views like view1, view2.....etc
then just call setVisibility(View.VISIBLE,view1,view2)
public static void setVisibility(int visibility, View... views){
for (View view : views){
view.setVisibility(visibility);
}
}
Related
I have ScrollView layout (or other layout type it doesn't mater) which has child views. And this parent layout has paddingLeft and paddingRight. I want to have this padding set for each child, but sometimes I have exception where I want that child to reach edges of the display completely (for example TextView with background color). Is there any way how to allow this to happen? I don't wanna set padding for every single child separately.
You told us what you want: "sometimes a Child shouldn't have to respect its Parent padding", so the special behaviour should occurs on Children.
The solution is to EXTEND Child's main View in which it chooses its MARGIN by default and then create a "Child.setNoMargins()" method that removes them from itself when required.
public static class ExtendedTextView extends TextView {
private boolean mHasNoMargins = false;
public ExtendedTextView(Context context) {
super(context);
}
public void setNoMargins() {
mHasNoMargins = true;
if (!isInLayout() && isAttachedToWindow()) requestLayout();
}
#Override
public void setLayoutParams(ViewGroup.LayoutParams params) {
if (!mHasNoMargins && (params instanceof ViewGroup.MarginLayoutParams)) {
((ViewGroup.MarginLayoutParams)params).setMarginStart(20);
((ViewGroup.MarginLayoutParams)params).setMarginEnd(20);
}
super.setLayoutParams(params);
}
}
In this way all created "ExtendedTextView" have default Left/Right margins until you call "setNoMargins()".
Obliviously my code works only if parent ViewGroup supports LayoutParams having Margins (most of them).
This is what my HorizontalScrollView looks like:
<HorizontalScrollView
android:layout_below="#id/saved_circuits_title"
android:id="#+id/saved_circuits_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="#+id/saved_circuits_scroll"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
In my HomeActivity I have the following relevant code that populates the HorizontalScrollView with bitmaps
onCreate{
...
this.savedCircuitsScroll = (LinearLayout) findViewById(R.id.saved_circuits_scroll);
...
}
updateSavedCircuits(){
...// code to make an ImageView from a retrieved bitmap
newImageImage.setOnClickListener(this.thumbnailListener);
this.savedCircuitsScroll.addView(newImageImage);
...
}
How do I use Espresso to scroll to an ImageView at a specified index in my HorizontalScrollView and click it?
What I've tried
I do not have ID's in my layout xml so an approach such as this does not work:
onView( withId( R.id.button)).perform( scrollTo(), click());
I know you can click on an item by index in a RecyclerView and tried finding an analogous approach for HorizontalScrollViews:
onView(withId(R.id.saved_circuits_scroll))
.perform(HorizontalScrollViewActions.actionOnItemAtPosition(0, click()));
Except HorizontalScrollViewActions does not exist.
or following this blog I tried the following to at least click an item in the HorizontalScrollView at a specified index:
// Click item at position 3
onView(withHorizontalScrollView(R.id.scroll_view).atPosition(3)).perform(click());
// Convenience helper
public static HorizontalScrollViewMatcher withHorizontalScrollView(final int horizontalScrollViewId) {
return new HorizontalScrollViewMatcher(horizontalScrollId);
}
except HorizontalScrollViewMatcher does not exist.
What do we do for HorizontalScrollView? It isn't a descendant of ScrollView so the answer here suggests I need to implement my own custom ViewAction. All I want to do is scroll to an item in a HorizontalScrollView by index and click it. Is this really needed? If this is what I need to do, how do I go about implementing this custom ViewAction?
In my case I got it by using:
onView(allOf(withId(R.id.itemTextView), withEffectiveVisibility(Visibility.VISIBLE), withText(R.string.categories))).perform(scrollTo(), click())
R.id.itemTextView is a TextView (with text R.string.categories) added dynamically to the LinearLayout:
<HorizontalScrollView>
<LinearLayout>
... [child added dynamically]
</LinearLayout>
</HorizontalScrollView>
Try to add this matcher.
public static Matcher<View> withIdAndParentId(final int viewId, final int parentId) {
Assert.assertTrue(viewId != -1);
Assert.assertTrue(parentId != -1);
return new TypeSafeMatcher<View>() {
#Override
public void describeTo(Description description) {
}
#Override
public boolean matchesSafely(View view) {
return view.getId() == viewId && isThereParentWithIdInHierarchy(view);
}
private boolean isThereParentWithIdInHierarchy(View view) {
ViewParent viewParent = view.getParent();
if (viewParent == null || !(viewParent instanceof ViewGroup))
return false;
ViewGroup parent = (ViewGroup) viewParent;
return parent.getId() == parentId || isThereParentWithIdInHierarchy(parent);
}
};
}
This is the way to use it :
onView(withIdAndParentId(R.id.YOUR_PARTICULAR_VIEW_ID, R.id.horizontalScrollViewId)).perform(scrollTo(), click());
Hope, it helps.
OK so in my particular case I found out that my scroll views had no ID associated with them (or none that I could reach reasonably, hence I couldn't use Mody's answer). However, they did have a tag associated with them so I could use Espresso's withTagValue ViewMatcher instead. Each view was associated with a circuitProject object (of course for you it may be different). And I have access to the following:
ArrayList<CircuitProject> circuitProjects = new ArrayList<>();
The index of a circuitProject object happens to be the position of the associated view in the HorizontalScrollView. The tag is the folder the circuitProject object is saved to. From here it is straightforward to get the behaviour I need with Espresso scrolling to a particular index in the HorizontalScrollView:
onView(withTagValue(withStringMatching(circuitProject.getFolderID()))).perform(scrollTo(), click());
I have the following scenario:
In a layout, I have imageviews aligned horizontally and vertically as shown in image.
First, which layout should be used for this purpose? RelativeLayout or FrameLayout? ListView inside the layout?
Also, instead of writing setOnClickListener for every imageview, how can I write just one click listener to get the clicked imageview?
A GridView is perfect for this. For more information on GridView, look here.
As for your onClickListener question: there is no easy way to do this, but what you can do is something like this:
Have an array containing every ImageView id like so:
public static final int[] IMAGE_VIEWS = {R.id.imageView1, R.id.imageView2, R.id.imageView3 /*etc*/}; //Make sure to list from the first imageview to the last image view in correct order
Define an onClickListener
private View.OnClickListener imageViewListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i < IMAGE_VIEWS.length; i++) {
if (v.getId() == IMAGE_VIEWS[i]) {
doSomethingWithImageViewClick(i); //if ImageView 4 was clicked, variable 'i' will be 3 (because arrays start at index = 0).
}
}
}
}
Set the onClickListeners for all your imageViews:
final ImageView view1 = (ImageView) view.findViewById(R.id.imageView1);
view1.setOnClickListener(imageViewListener);
//etc
Use 'GridView' in the layout and use 'setOnItemClickListener' to handle click events,
You can find more details in below link
GridView.
GridView can achieve the effect. I think you can look at this Grid View.
In Asyntask, I want to change textswitcher text and If I add new view, app crash.
Code sample:
textSwitcher.setInAnimation(MainActivity.this,android.R.anim.slide_in_left);
textSwitcher.setOutAnimation(MainActivity.this, android.R.anim.slide_out_right);
TextView tv=new TextView(MainActivity.this);
tv.setGravity(Gravity.CENTER | Gravity.LEFT);
tv.setTypeface(custom_font);
tv.setTextColor(Color.parseColor("#00285E"));
textSwitcher.addView(tv);
last line gives error after I decided to remove all views and I added textSwitcher.removeAllViews(); , then it gives null pointer. What do you think for fix ?
ViewSwitcher can only have two children, as it says on the documentation for that class. I personally have not seen anyone using ViewSwitcher, it is an old class and you can get the same effect or better on your own with ObjectAnimators now anyway.
You can create your own ViewGroup that let's you switch any view for any other. If it were me, I would just extend FrameLayout and simply add something like this:
public void switchView(View view) {
// add the new view and reveal
view.setAlpha(0);
addView(view);
view.animate().alpha(1f).start();
if (getChildCount() > 0) {
// simultaneously remove the previous view
final View child = getChildAt(0);
child.animate().alpha(0).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animator) {
// remove the child when the animation ends
removeView(child);
}
}).start();
}
}
This is completely arbitrary behaviour. You can overwrite ViewAnimator similar to ViewSwitcher class and replace the 0 / 1 handling by a variable subview count. Really easy!
when i use sliding drawer, i want a layout to gone so that sliding drawer will not be blocked.
However, i tried many ways such as
view = (View)findViewById(R.id.layout_latestcontent);
view.setVisibility(View.GONE);
linear = (LinearLayout)findViewById(R.id.layout_latestcontent);
linear.setVisibility(2);
Both also cannot.
public void onDrawerClosed() {
//view = (View)findViewById(R.id.layout_latestcontent);
//view.setVisibility(View.VISIBLE);
}
public void onDrawerOpened() {
//view = (View)findViewById(R.id.layout_latestcontent);
//view.setVisibility(View.GONE);
}
Even implements both function also cannot
How to make the entire layout gone?
You can apply value 2 (or any of this) only in android:visibility view's property. If you wants to change View visibility from code you should use constants View.VISIBLE, View.INVISIBLE or View.GONE (constant values 0, 4, 8). linear.setVisibility(View.GONE) instead of linear.setVisibility(2) .