I can get an ActionBar's view using getCustomView. Is there a way to get its TextView from that?
Not in any way that is going to be reliable across OS versions and devices.
If you are attempting to set the title of the action bar, please use setTitle() on ActionBar. If you are trying to style the title, you should be able to do that via a theme.
Or, hide the title and render your own via setCustomView().
Try recursively? (might not be a good solution though!)
static List<TextView> textViews = new ArrayList<TextView>();
public static <T> void searchRecursively(View parent, Class<T> clazz)
{
if(clazz.isInstance(parent)) textViews.add(clazz.cast(parent));
if(parent instanceof ViewGroup)
{
ViewGroup vg = (ViewGroup) parent;
int count = vg.getChildCount();
for(int i = 0; i < count; i++)
{
View v = vg.getChildAt(i);
searchRecursively(v);
}
}
}
Use it like:
searchRecursively(theView, TextView.class);
Related
It is possible to get a list of all the currently displayed/on-screen android UI elements?
For example, if I have a app that look like this:
I would get a list that would contain:
TextView (Hello World!)
RelativeLayout (Or whatever the parent container is)
Etc if there were more elements
This would be great in the case I don't know the ID's, or even what UI elements will appear on screen, but I still want to hide/show them.
You can achieve this by using the following manager, nice and clean!
Use it anywhere you want and you'll get a list of the view and all its children.
(Needs to be done recursively)
LayoutManager.getViews(getWindow());
public class LayoutManager
{
private static List<View> views;
public static List<View> getViews(Window window) {
return getViews(window.getDecorView().getRootView(), true);
}
public static List<View> getViews(final View view, boolean starting)
{
if (starting) {
views = new ArrayList<>();
}
views.add(view);
/** Search in each ViewGroup children as well */
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
getViews(viewGroup.getChildAt(i), false);
}
}
return views;
}
}
I need to change the text color of all buttons in a view programmatically.
Right now I'm modifying them one by one like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = inflater.inflate(R.layout.fragment_screen_dialer, container, false);
Button b = (Button) view.findViewById(R.id.button0);
b.setTextColor(value);
b = (Button) view.findViewById(R.id.button1);
b.setTextColor(value);
But since there are a lot of buttons I want to modify them all at once? How can this be done?
Iterate through all children of your layout, checking if next view is instance of Button or its subclass:
ViewGroup viewgroup = (ViewGroup) findViewById(R.id.your_layout);
int count = viewgroup.getChildCount();
for (int i=0; i < count; i++){
View view = viewgroup.getChildAt(i);
if (view instanceof Button){
(Button)view.setTextColor(value);
}
}
This will work if your buttons lays on the same level. Otherwise you need to build a recurrent function similar to this:
public void setNewColor(View view, int value){
if (view instanceof Button){
((Button) view).setTextColor(value);
}
else if (view instanceof ViewGroup){
ViewGroup viewgroup = (ViewGroup)view;
int count = viewgroup.getChildCount();
for (int i=0; i < count; i++){
View viewNext = viewgroup.getChildAt(i);
setNewColor(viewNext, value);
}
}
}
and apply it to your layout:
setNewColor(findViewById(R.id.your_layout), your_color);
AFAIK, you can't modify the color or other property of layout elements in a view at once. You have to do how you are doing, i.e. set the color one by one.
However, you can create a button style in style.xml and assign the syle to all buttons and whenever you will change style.xml it will effect all the buttons
You may have to iterate over all the views, and change colors of the buttons. Check this page for how to traverse all child view / view groups of your layout, including views (button) that are not direct children of your main layout
Including the two classes provided, you will write easy code like:
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
List<Button> buttons = Views.find(root, Button.class);
for (Button b: buttons)
b.setTextColor(value);
Do Android views have something equivalent to CSS class selectors? Something like R.id but usable for multiple views? I would like to hide some group of views independent of their position in the layout tree.
I think that you will need to iterate through all of the views in your layout, looking for the android:id you want. You can then use View setVisibility() to change the visibility. You could also use the View setTag() / getTag() instead of android:id to mark the views that you want to handle. E.g., the following code uses a general purpose method to traverse the layout:
// Get the top view in the layout.
final View root = getWindow().getDecorView().findViewById(android.R.id.content);
// Create a "view handler" that will hide a given view.
final ViewHandler setViewGone = new ViewHandler() {
public void process(View v) {
// Log.d("ViewHandler.process", v.getClass().toString());
v.setVisibility(View.GONE);
}
};
// Hide any view in the layout whose Id equals R.id.textView1.
findViewsById(root, R.id.textView1, setViewGone);
/**
* Simple "view handler" interface that we can pass into a Java method.
*/
public interface ViewHandler {
public void process(View v);
}
/**
* Recursively descends the layout hierarchy starting at the specified view. The viewHandler's
* process() method is invoked on any view that matches the specified Id.
*/
public static void findViewsById(View v, int id, ViewHandler viewHandler) {
if (v.getId() == id) {
viewHandler.process(v);
}
if (v instanceof ViewGroup) {
final ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
findViewsById(vg.getChildAt(i), id, viewHandler);
}
}
}
You can set same tag for all such views and then you can get all the views having that tag with a simple function like this:
private static ArrayList<View> getViewsByTag(ViewGroup root, String tag){
ArrayList<View> views = new ArrayList<View>();
final int childCount = root.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = root.getChildAt(i);
if (child instanceof ViewGroup) {
views.addAll(getViewsByTag((ViewGroup) child, tag));
}
final Object tagObj = child.getTag();
if (tagObj != null && tagObj.equals(tag)) {
views.add(child);
}
}
return views;
}
As explained in Shlomi Schwartz answer. Obviously this is not as useful as css classes are. But this might be a little useful as compared to writing code to iterate your views again and again.
I set tag for UI widgets and I want to retrieve a list of View that has a specific tag. Using View.findViewWithTag("test_tag") just return one View not all view that support tag.
Any help appreciated.
You shouldnt expect an array of views from this method, since the method signature itself tells that it will return a single view.
public final View findViewWithTag (Object tag)
However, what you may do is to get your layout as ViewGroup and then iterate through all the child views to find out your desired view by doing a look-up on their tag. For example:
/**
* Get all the views which matches the given Tag recursively
* #param root parent view. for e.g. Layouts
* #param tag tag to look for
* #return List of views
*/
public static List<View> findViewWithTagRecursively(ViewGroup root, Object tag){
List<View> allViews = new ArrayList<View>();
final int childCount = root.getChildCount();
for(int i=0; i<childCount; i++){
final View childView = root.getChildAt(i);
if(childView instanceof ViewGroup){
allViews.addAll(findViewWithTagRecursively((ViewGroup)childView, tag));
}
else{
final Object tagView = childView.getTag();
if(tagView != null && tagView.equals(tag))
allViews.add(childView);
}
}
return allViews;
}
int tags = 6;
for (int index = 0; index < tags; index++) {
try{
TextView txtView = (TextView)getView().getRootView().findViewWithTag("txtTag-"+index);
txtView.setText(" TWitter/ #MOIALRESHOUDI ");
} catch (Exception e){}
}
hope this helps someone!
Its very simple in my use case. For example there are twelve imageviews with a same tag in a layoyut.
When findViewWithTag("image") calls on. It will simply give first index single imageview in from a layout. The solution is simple when you got a imageview with that tag, simply set that imageview tag to empty string. Next time in iteration when findViewWithTag("image") calls on. It will simply give you the next imageview.
for(int inf = 0; inf < albumPageImagesInfoList.get(cardPosition); inf++){
ImageView imageView = inflateView.findViewWithTag("image");
if(imageView!=null){
imageView.setId(uivid);
imageView.setTag("");
imgIndexId++;
}
}
I have the same View inflated (from XML) multiple times. When I call findViewById(R.id.my_layout).setVisibility(View.GONE) I want to apply it on all such views.
How do I do that?
There isn't a version of findViewById() that returns all matches; it just returns the first one. You have a few options:
Give them different ids so that you can find them all.
When you inflate them, store the reference in an ArrayList, like this:
ArrayList<View> mViews = new ArrayList<View>();
Then when you inflate:
LayoutInflater inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mViews.add(inflater.inflate(R.layout.your_layout, root));
Then when you want to hide them:
for (View v : mViews) { v.setVisibility(View.GONE); }
Depending on what you're doing with these Views, the parent layout may have a way of accessing them. E.g., if you're putting them in a ListView or some such. If you know the parent element you can iterate through the children:
ViewGroup parent = getParentSomehow();
for (int i = 0; i < parent.getChildCount(); ++i) {
View v = parent.getChildAt(i);
if (v.getId() == R.id.my_layout) {
v.setVisibility(View.GONE);
}
}
If the above options don't work for you, please elaborate on why you're doing this.
Modify on the View that holds the inflated layout.
E.g:
If you have
View v = inflater.inflate(.... );
you change the visibility onto this view. v.setVisibility(View.GONE);