I use my own icon image as indicator for ExpandableListView, but the icon seems to be stretched, I tried to put the image file in /drawable and /drawable-hdpi with no luck. If I do not use my own icon, the built-in Android one looks nice, so I wonder is there any restriction on image dimension, or is there anything I've done wrong?
Thanks!
Whatever image you are using as your group indicator, make it a 9 patch (xxx.9.png) image and set its stretchable areas to around the border pixels (which probably may be transparent). It will prevent stretching of image from the middle.
The expandable list is a pain. It always stretches the icons. An easy solution is to use a nine patches images which contains only a stretchable pixel at both top and bottom. Thus only those two pixels are stretched and the rest of your image remains unmodified.
hope this make sense
If you want to do this all via coding, without using a different image, this is how I got this working.
(1) Setting the group indicator to null
(2) Including my custom group indicator in the group Layout.
(3) Having an groupClickListener that changes the state of you indicator.
Code Snippets :
(1) mListView.setGroupIndicator(null);
(2) Included my indicator in the group layout.
<ImageView
android:id="#+id/help_group_indicator"
android:layout_width="#dimen/help_group_indicator_dimension"
android:layout_height="#dimen/help_group_indicator_dimension"
android:layout_marginTop="#dimen/help_group_indicator_dimension"
android:src="#drawable/down_icon" />
(3)
mListView.setOnGroupClickListener(new OnGroupClickListener() {
#Override
public boolean onGroupClick(ExpandableListView parent, View clickedView, int groupPosition, long rowId) {
ImageView groupIndicator = (ImageView) clickedView.findViewById(R.id.help_group_indicator);
if (parent.isGroupExpanded(groupPosition)) {
parent.collapseGroup(groupPosition);
groupIndicator.setImageResource(R.drawable.down_icon);
} else {
parent.expandGroup(groupPosition);
groupIndicator.setImageResource(R.drawable.up_icon);
}
return true;
}
});
Related
It seems that every angle I manage to find doesn't end up working in the way I need it to. My goal is to be able to customize the positioning and size of any scrollbar on any view, be it a recyclerview, gridview, or listview. I've tried using layer-list xmls to adjust the height and positioning, a Seekbar turned vertically, as well as trying to create my own scrollbar thumb and track using imageviews.
In terms of the layer-list, it just didn't have an effect on the scrollbar at all. The other two attempts at a solution (using a Seekbar, using individual imageviews) were nearly effective, except I needed the current scrolled position (getScrollY()) to be able to make the scrollbars I made actually accurate instead of just visually being a scrollbar. However, even though getScrollY() is defined for recyclerview, gridview and more, it always returns a 0, so I am unable to get that information (except for scrollviews, perhaps; I believe that's the only view type that properly returns a getScrollY() value).
Is it even possible to customize the scrollbar in this manner? I'd be keen to see references or documentation that can point me in the right direction. It feels like this is generally a non-issue for most developers on Android, or at least in general isn't something many people have asked for.
Edit
To assist in visualizing what I have and what I desire, here's a screenshot of the scrollbar as it is right now:
The following image is marked up to show what my intended outcome for this scrollbar would be:
Views have the capability for a scrollbar but a lot don't show them by default.
So any View has a whole load of XML attributes to customise the appearance, size and position.
But these are useless if not shown.
A lot of ViewGroups sub classes setWillNotDraw to be true and this removes the capability to draw the built in scrollbars of the View.
So to get any view to show it's built in scrollbars you need to the setWillNotDraw(false)
Getting any View to show it's built in scrollbars is Step 1 but again not all Views Calculate automatically the length and position of scroll hence they return 0 for the scroll position.
The View has to implement the following methods and return the appropriate numbers for the scroll position to be correct and things like getScrollY to return more than 0
// Length of scrollbar track
#Override
protected int computeHorizontalScrollRange() {
return (int) value;
}
// Position from thumb from the left of view
#Override
protected int computeHorizontalScrollOffset() {
return (int) value;
}
#Override
protected int computeVerticalScrollRange() {
return (int) value;
}
#Override
protected int computeVerticalScrollOffset() {
return (int) value;
}
Off Course some View sub classes don't use the built in ones but draw there own.
I have to display posts from a json feed inside a RecyclerView and I have a layout for how a single row looks inside the RecyclerView as follows
I have not yet implemented the bottom part in my actual layout which contains the red and green boxes from the figure above and my layout looks like this
I am also implementing Swipe to delete with undo which as you know requires a FrameLayout as the root , and 2 nodes under it, one showing the normal area and one showing the layout which is revealed on swipe. In my case, when I swipe the item, this is what you will see.
Now the problem is, there are 13 views per row and I don't like the odds of that, I will be displaying a maximum of 100 items in the RecyclerView at a given time and as you see it would lead to a large number of Views.
I have certain approaches in mind to make a custom View to reduce the number of Views in the row. What would be the best way according to you to optimise this View or should I say, reduce the number of Views per row in the RecyclerView. I get all the data from JSON and the central text area needs to be expandable in nature with a Read More or Read Less depending on its state.
Approach 1
Slight simplification
In this approach, I will combine the person's profile picture at the top left, the TextView with the name and updated time into a single Custom View, in other words, it will extend from View, have its own canvas for drawing the Bitmap, the Strings but I'll have to manually code RTL and LTR and other items using a StaticLayout in Android. I need the central text area to be expandable in nature so I will stick with one of the Expandable Views everyone keeps mentioning on stackoverflow.
Approach 2
Highly modular Custom UI component.
The entire diagram composed of the user's image, text with name, time, central text and image can be made into a single CustomView, I am not sure how I can make this expandable yet because a StaticLayout once initialised in Android cannot be modified. What do you think? Is this the correct approach to go? I will end up having only 4 children per row if I make the entire thing a single View. Is that a valid use case for custom Views?
Well, I found the answer myself. There are two types of post items I am dealing with, ones that contain an ImageView to display a 16:9 post image and the ones that don't. My RecyclerView was lagging heavily in the scroll operation till now since I had a single layout file which had an ImageView with its width set to match_parent and height set to wrap_content. When I was scrolling, the posts with Images were using Glide to load images and were calling requestLayout() since the size of those items were changing. This was resulting in too many requestLayout() calls causing the heavy lag while scrolling.
How did I fix this?
I made an Adapter which was sectioned having 2 types of rows.
#Override
public int getItemViewType(int position) {
if (mResults != null) {
return mResults.get(position).getPicture() != null ? IMAGE : NO_IMAGE;
}
return NO_IMAGE;
}
Based on whether the result at the current position contains an Image in the post or not, I had my onCreateViewHolder method modified to set a predefined size for the ImageView incase my item had a post image.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == IMAGE) {
view = mLayoutInflater.inflate(R.layout.row_post_image, parent, false);
RowImageHolder holder = new RowImageHolder(view);
//To set the width and height of the ImageView of our image in the post, we get its LayoutParams and adjust its width and height to maintain 16:9 ratio
ViewGroup.LayoutParams params = holder.mPostPicture.getLayoutParams();
params.width = mPostImageWidth;
params.height = mPostImageHeight;
holder.mPostPicture.setLayoutParams(params);
return holder;
} else {
view = mLayoutInflater.inflate(R.layout.row_post_image, parent, false);
RowNoImageHolder holder = new RowNoImageHolder(view);
return holder;
}
}
And thats all which needs to be done. The onBindViewHolder sets an image if the type of the item supports an image. The benefit is that space is reserved in advance for those items that have images and the performance of the RecyclerView on scroll improves tremendously. I achieved this without using any custom views so far :)
Hi I'm trying to add an activity that displays 4 images (imagine a square cut to quarters) where each image shows a different one when clicked, I have tried a few layouts using image buttons to no avail but then read here my answer is a grid view using image pager but when implementing this I get small images spaced quite far apart in grid view is there a better way please?
if it's always 2x2 images you can simply use a vertical linear layout and two horizontal layouts in it and then put your images as ImageButton or ImageView inside the horizontal layouts...
if it needs to be dynamic a gridlayout would probably be a good idea...
however, you need to provide more detailed information on what the issue is, if you need a more detailed answer...
(edit: I meant gridview, gridlayout is only available since api level 14)
You can use a RelativeLayout in order to add your ImageButtons and have all the control to your hands for location of buttons, size etc.
A different point of view, is to break your screen into 4 Rectangles (Rects).
Something like this :
Rect upLeftRect = new Rect(0,0,screenWidth/2 , screenHeight/2);
Rect upRightRect = new Rect(screenWidth/2,0,screenWidth,screenHeight/2);
Rect downLeftRect = new Rect(0,screenHeight/2, screenWidth/2 , screenHeight);
Rect downRightRect = new Rect(screenWidth/2, screenHeight/2, screenWidth,screenHeight);
The, attach an onTouchListener on your relativeLayout, something like this in your constructor:
yourRelativeLayout.setOnTouchListener(this);
And finally , inside the onTouch method you will have something like this :
#Override
public boolean onTouch(View v, MotionEvent e){
if(upLeftRect.contains( ( int ) e.getX(), (int) e.getY){
// do whatever you want, i guess that you want some alpha animation or something like this
}else if(upRightRect.contains( (int) e.getX(), (int) e.getY(){
// bla bla.. :)
} // do the rest conditions your self!!
Hope that helped!
I'm currently developing an android app and I would like to achieve an effect to which I haven't found an answer to, even after some searching.
The effect I would like to obtain is over an image. Usually when you press an image, you apply some sort of tint over the image in order to show some feedback, but I would like to go a little bit further, I wouldn't like to apply a tint but a sort os scale over the image.
E.g. I have the following image, Normal Image, and if I press the image (and while I keep it pressed), I would like the image to shrink a bit, like this Pressed Image
N.B.- The black part would not be part of the image, but part of the background. The image would only be the blue square.
Thank you for any help! :)
P.S.- I couldn't post the images here because I don't have enough reputation.
You need to set the onTouchListener of your ImageView that displays the image, so that it replaces the displayed image. This is the listener that runs when you press or unpress the view (in this case the image).
Sample Code:
ImageView iv = (ImageView)findViewById(R.id.my_image_view);
iv.setOnTouchListener(new ImageView.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent e) {
if (e.getAction()==MotionEvent.ACTION_DOWN)
// Write code here that sets the imageview to display the pressed image
else if (e.getAction()==MotionEvent.ACTION_UP)
// Write code here that sets the imageview to display the unpressed image
}
});
Reference to onTouchListener: http://developer.android.com/reference/android/view/View.OnTouchListener.html
Reference to ImageView (for replacing the displayed image):
http://developer.android.com/reference/android/widget/ImageView.html
today i tried to make my listview a bit more dynamic. So i created a white ninepatch-image and added a colorfilter with the .setColorFilter method. That's not the problem.
But after applying this, everytime i scroll the Image is scaling wrong (randomly) so lets say my item is 100dp high with some text. After scrolling the item is still 100dp high and all text is shown but the image in the Background only uses 50dp now.
Here's my code:
here how i set the Colorfilter:
orgleftbox = context.getResources().getDrawable(R.drawable.list_bubble);
orgleftbox.setColorFilter( 0xff00c0ff, Mode.MULTIPLY );
and here how i add it in my adapter
v = inflater.inflate(R.layout.list_view_item, null);
TextView t = (TextView)v.findViewById(R.id.text);
t.setBackgroundDrawable(orgrightbox);
I hope someone could help me. Because this bug is annoying me ;(
Your interpretation is correct, you cannot use the Drawable on several Views. The Drawable has a size set by its View, so if you attach it to several Views at the same time, it won't work properly unless the Views have exactly the same dimension.
i was able to fix my problem on my own. So i answer this for everybody else ;).
The problem was that i loaded my drawable once in the constructor, because i thought so i won't have to load it for each listitem new. But the android-system handles them as the same memory object. so every listitem-background uses the same mem-space (i hope it isn't wrong, i think so). If i start scrolling the next listitem will be declared and changes the height and width of its background to its needs, example the next item is only 50dp high it changes the saved value to this one. Now every other background of the list will change more or less to this height too.
The simple fix is, that you have to load and apply the colorfilter for each item new. espec. in the getView Method.
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
View v = null;
leftbox = (NinePatchDrawable) r.getDrawable(R.drawable.bubble_green);
leftbox.setColorFilter( 0xff00c0ff, Mode.MULTIPLY );
v = inflater.inflate(R.layout.list_view_item_right, null);
TextView t = (TextView)v.findViewById(R.id.text);
t.setBackgroundDrawable(leftbox);
i hope this answer was useful.
EDIT (Thousand times simpler):
If you only want to apply a colorFilter to a Layout(Textview...) do it this way (thanks Pasha):
TextView t = (TextView)v.findViewById(R.id.text);
t.getBackground().setColorFilter(0xff00c0ff, Mode.MULTIPLY );