I work with an SDK that provides a rectangular glsurfaceview through a callback.
I want to be able to render this view in a circular layout. (i.e.) I would like to display the view on a circular view
I have tried using masking layout such as using a maskable layout https://github.com/christophesmet/android_maskable_layout (works great for images, not so much for videos)
How do I go about clipping and rendering this as a circle?
(The background is constantly changing, so i cant overlay a transparent view on top of this video view. The aim is to have a rectangular glsurface view on top of which there is a circular glsurface view)
**UI Objective : **
I have pretty much the same requirement with a project right now, which involves masking a GLSurfaceView provided by PexKit. The solution that works for me is making a subclass of FrameLayout (or any other ViewGroup) and placing the GLSurfaceView inside it.
Then in the FrameLayout subclass use canvas.clipPath:
private Path clippingPath;
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
int radius = Math.min(w, h)/2;
clippingPath = new Path();
clippingPath.addCircle(w/2, h/2, radius, Path.Direction.CW);
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();
canvas.clipPath(clippingPath);
super.dispatchDraw(canvas);
canvas.restoreToCount(count);
}
Related
I have a custom LinearLayout class which I'm using to clip all of its child Views through Canvas#clipPath():
public class MaskedLinearLayout extends LinearLayout {
protected Path mMaskingClip = new Path();
(...)
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Update clipping path
mMaskingClip.reset();
(...)
mMaskingClip.close();
}
#Override
public void dispatchDraw(Canvas canvas) {
int save = canvas.save();
canvas.clipPath(mMaskingClip);
super.dispatchDraw(canvas);
canvas.restoreToCount(save);
}
}
The code above works great, but the background Drawable that I've set for the same MaskedLinearLayout is not clipped to the path that I've defined (only its children).
How should I accomplish this? Some things that I've tried include overriding method onDraw() (with similar code shown in method dispatchDraw() above) and setting its background Drawable boundaries manually (Drawable#setBounds()), both without success.
Note that I cannot use static Drawables in this layout, because the latter should be able to be resized/masked dynamically while being displayed on the screen.
Thank you in advance for any answer.
I have a horizontal scrollview (which has a single view group inside, obviously) which I'm adding some views into when my activity is created. I want a view to start and end at the middle so I need to give some paddings to right and left respectively to the first and last view. Since the sizes are not measured at onCreate, I calculated them on onSizeChanged but the sizes of views are not calculated yet so no prevail there.
public void add(ArrayList<String> list) {
for(String string : list) {
View view = inflater.inflate(R.layout.textview_with_indicator, null);
views.add(view);
((TextView)view.findViewById(R.id.text)).setText(string);
content.addView(view);
}
invalidate();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if(paddingSet && null != views && views.size() > 0) {
int paddingLeft = getWidth() - (views.get(0).getWidth()/2);
int paddingRight = getWidth() - (views.get(views.size()-1).getWidth()/2);
setPadding(paddingLeft, getPaddingTop(), paddingRight, getPaddingBottom());
paddingSet = true;
}
}
I think I need to observe the size change of views instead of whole content but I have no idea how to implement it. I tried to implement onGlobalFocusChanged to scrollview but could not make it work. Any ideas would be appreciated.
I have a custom ScoreView that consists of two lines of text (a name and a score). Behind that text, I am drawing a bar representing the score.
I have a fragment that contains three such ScoreViews. When I update the ScoreViews with a new name or score, everything works fine. However, if I update the rectangle behind them, only the first rectangle is redrawn.
The end result is something like this:
All three ScoreViews should have a gray bar behind the text.
To prevent the possibility of my fill color attribute causing this, I am statically setting the bar's color in the ScoreView.
ScoreView snippet:
public class ScoreView extends View {
public void setFillPercent(float percent) {
mFillPercent = percent;
mFillRect = new Rect(getLeft(), getTop(), getLeft() + Math.round(mFillPercent*getWidth()), getBottom());
invalidate();
requestLayout();
}
#Override
protected void onSizeChanged (int w, int h, int oldw, int oldh) {
mFillRect = new Rect(getLeft(), getTop(), getLeft() + Math.round(mFillPercent*w), getBottom());
mTextXPos = getLeft() + 20; // TODO dp?
mNameTextYPos = h/2 - (int)mNameTextSize;
mScoreTextYPos = h/2 + (int)mScoreTextSize;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(mFillRect, mFillPaint);
canvas.drawText(mName, mTextXPos, mNameTextYPos, mNameTextPaint);
canvas.drawText(String.valueOf(mScore), mTextXPos, mScoreTextYPos, mScoreTextPaint);
}
}
In my fragment, I call:
oneScoreView.setFillPercent(.5f);
twoScoreView.setFillPercent(.5f);
threeScoreView.setFillPercent(.5f);
I set a breakpoint in onDraw() and I can see that it is being called, and that mFillRect has the correct size and position. It simply doesn't get displayed.
I also discovered that if I rearrange the three ScoreViews, it is always the first ScoreView that updates properly.
I am not sure, but mFillRect = new Rect(getLeft(), getTop(), getLeft() it means you set offset left and top of the view, but then you use this rectangle to draw inside the same view. I think it's just out of view's canvas area, that's why you cannot see it. I might be wrong though.
#Dan S, gave the below statement in this post -> display a still image map
Then using a second ImageView (for the indicator) draw it on top and
move it to the correct place on the screen and make sure the
background in this View is transparent as well as the background of
your indicator
How can I create the second ImageView for my indicator? It should be transparent imageview as well as the indicator image.
UPDATE:
I am asking here on how to overlap my image map ImageView and transparent indicator ImageView in order to mark the current location.
An ImageView is transparent by default.
Your indicator image resource should have a transparent background (e.g. transparent .PNG image).
Just set the ImageView's imageResource or backgroundResource to the PNG file.
So your code for creating your ImageView will be something like this:
ImageView myImageView = new ImageView(context);
myImageView.setBackgroundColor(0x0); // not needed - it's the default
myImageView.setImageResource(R.drawable.indicator_icon);
but again, this's the default and you still have to make sure your image's background is transparent otherwise the ImageView's background won't matter.
UPDATE: following #eros update of the question, here's an updated answer:
There are two options, i can think of, to achieve positioning of one imageview on top of the other:
use the LayoutParams and set the margins to the position the indicator imageview
draw the indicator imageview on top of the map bmp's canvas
personally i like the first option better because future changes won't force you to repaint the indicator.
here's a class demonstrating option (1):
public class MyMapView extends RelativeLayout {
private ImageView mBackImageView;
private ImageView mIndicatorImageView;
public MyMapView(Context context) {
super(context);
mBackImageView = new ImageView(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
mBackImageView.setImageResource(R.drawable.image1);
mBackImageView.setScaleType(ImageView.ScaleType.FIT_XY);
addView(mBackImageView, params);
mIndicatorImageView = new ImageView(context);
RelativeLayout.LayoutParams indParams = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mIndicatorImageView.setImageResource(R.drawable.image2);
addView(mIndicatorImageView, indParams);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
centerIndicatorPosition();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerIndicatorPosition();
}
// #eros: this's the part you want. this method just centers the indicator view
// but if you have the relative position like you say, use it for the margins
private void centerIndicatorPosition() {
int xPos = (getMeasuredWidth() - mIndicatorImageView.getMeasuredWidth()) / 2;
int yPos = (getMeasuredHeight() - mIndicatorImageView.getMeasuredHeight()) / 2;
((RelativeLayout.LayoutParams)mIndicatorImageView.getLayoutParams())
.setMargins(xPos, yPos, 0, 0);
}
}
i want to draw a graph in a area and i used a linear layout as area.i want to set the size of the graph area,which should be compatible to small,medium ,default emulators etc.i need to set the size for graph area,how can i do it in xml file
for eg in blackberry we use Display.getWidth();Similar is there way to get the width of the display either programmatically or in xml
To expand my area, i did like this, in below image (just added label,which gets an height)
image
To expand it ,i added somemore like this
image1
Regards
Rakesh Shankar.p
You can't get the width from the xml. You can get it programmatically from your View:
#Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
}
onSizeChanged is called whenever the size of the View changes (including the time the View is first constructed). Alternatively you can use getWidth() inside onDraw:
#Override
public void onDraw(Canvas canvas) {
int width = this.getWidth();
}