I have the following custom relative layout:
public class CircleView extends RelativeLayout implements OnDragListener {
private DropCallback onDrop = null;
private ImageButton imageButton = null;
private int radius = -1;
private double step = -1;
private double angle = -1;
private static final int CENTER_ID = 111;
public CircleView(Context context, DropCallback onDrop, int radius, List<View> views) {
super(context);
this.onDrop = onDrop;
this.radius = radius;
this.step = (2 * Math.PI) / views.size();
this.initView(context, views);
}
private void initView(Context context, List<View> views) {
RelativeLayout.LayoutParams layoutParamsView = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
this.setLayoutParams(layoutParamsView);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
this.imageButton = new ImageButton(context);
this.imageButton.setId(CENTER_ID);
this.imageButton.setLayoutParams(layoutParams);
this.imageButton.setImageResource(R.drawable.ic_power_on);
this.imageButton.getBackground().setAlpha(0);
this.imageButton.setOnDragListener(this);
this.addView(this.imageButton);
for(View view : views) {
this.addView(this.placeView(view));
}
}
private View placeView(View view) {
view.measure(0, 0);
this.imageButton.measure(0, 0);
int x = (int)((view.getMeasuredWidth() / 2) + this.radius * Math.cos(this.angle));
int y = (int)((view.getMeasuredHeight() / 2) + this.radius * Math.sin(this.angle));
this.angle += this.step;
int deltaX = view.getMeasuredWidth();
int deltaY = view.getMeasuredHeight();
int deltaImageX = this.imageButton.getMeasuredWidth() / 2;
int deltaImageY = this.imageButton.getMeasuredHeight() / 2;
int xToDraw = ((x - deltaX) - deltaImageX);
int yToDraw = ((y - deltaY) - deltaImageY);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.ABOVE, CENTER_ID);
layoutParams.addRule(RelativeLayout.RIGHT_OF, CENTER_ID);
layoutParams.setMargins(xToDraw, 0, 0, yToDraw);
view.setLayoutParams(layoutParams);
return view;
}
#Override
public boolean onDrag(View view, DragEvent event) {
return this.onDrop.onDrop(view, event);
}
}
I have no xml layout file for this and it worked until now.
Today i changed the activity using this custom layout to be a Fragment and i now need to set the layout. Unfortunately something like the following isnt possible:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
return inflater.inflate(new CircleView(this, this, 240, this.views), container, false);
}
So how can i inflate my custom relative layout?
Just create an instance of Circle view and add it to container :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
CircleView circleView = new CircleView(this, this, 240, this.views);
...
return circleView;
}
You should create you xml layout, for example circle_view.xml:
<your_package.CircleView android:id="#+id/gcircle_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
and then:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
return inflater.inflate(R.layout.circle_view, container, false);
}
btw, you should implement constructors:
public CircleView(Context context){
super(context);
}
public CircleView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public CircleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
You can create the inflator like this:
LayoutInflater inflater = LayoutInflater.from(context);
Then use the inflator to inflate the needed.
Related
I want to change the height of the view and decrease height all the bottom view. This works well in the fragment, but does not work in the adapter.
I do not want to squeeze the main view, I need to increase only the size of containerAvatar.
public class OrderAdapter extends ArrayAdapter {
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.open_order_item, parent, false);
containerAvatar = convertView.findViewById(R.id.container_avatar_size);
imgAvatar = convertView.findViewById(R.id.img_open_order_avatar);
Glide.with(context)
.load("http://neuronovosti.ru/wp-content/uploads/2017/12/Drosophila-Brain-1024x1024.jpg")
.into(imgAvatar);
containerAvatar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final ViewGroup.LayoutParams lp = containerAvatar.getLayoutParams();
final ResizeAnimation a = new ResizeAnimation(containerAvatar);
a.setDuration(500);
a.setParams(lp.height, lp.height * 2);
containerAvatar.startAnimation(a);
}
});
return convertView;
}
public class ResizeAnimation extends Animation {
private int startHeight;
private int deltaHeight; // distance between start and end height
private View view;
public ResizeAnimation(View v) {
this.view = v;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
view.getLayoutParams().height = (int) (startHeight + deltaHeight * interpolatedTime);
view.requestLayout();
}
public void setParams(int start, int end) {
this.startHeight = start;
deltaHeight = end - startHeight;
}
#Override
public void setDuration(long durationMillis) {
super.setDuration(durationMillis);
}
#Override
public boolean willChangeBounds() {
return true;
}
That's what you need
Try with setLayoutParams() Method of View -
private void setDimensions(View view, int width, int height){
android.view.ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
Added it on your Adapter -
public class OrderAdapter extends ArrayAdapter {
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R.layout.open_order_item, parent, false);
containerAvatar = convertView.findViewById(R.id.container_avatar_size);
imgAvatar = convertView.findViewById(R.id.img_open_order_avatar);
Glide.with(context)
.load("http://neuronovosti.ru/wp-content/uploads/2017/12/Drosophila-Brain-1024x1024.jpg")
.into(imgAvatar);
containerAvatar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setDimensions(containerAvatar, 100, 100);
}
});
return convertView;
}
private void setDimensions(View view, int width, int height){
android.view.ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
}
I'm coding a ring menu that is going to put together several different types of view, which will have all the same size. The thing is that it works perfectly with native views, like ImageView, but when I try to put a custom labeled image view, it simply doesn't appear int the custom ViewGroup. It's also worth mentioning that when this view is declared in the XML file, outside de custom ViewGroup it is shown just fine, but as soon as I put it inside the ViewGroup, or declare it programatically, it vanishes. My guess is that I'm doing something weong inside the onLayout method, but I can't put my finger on it, since all coordinates and view sizes are correct according to the Log.
The XML file for the CompoundView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true">
<ImageView
android:id="#+id/header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="#drawable/ropeiconselector"/>
<TextView
android:id="#+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="WWWWWWWWWWWW"
android:background="#color/button"
android:layout_marginLeft="-10dp"
android:layout_centerVertical="true"
android:layout_toRightOf="#id/header"
android:padding="8dp"
/>
The code for the CompoundView (I omitted some unimportant methods)
public class CircularLabeledImageView extends RelativeLayout implements View.OnClickListener {
ImageView headerView;
TextView labelView;
boolean isOpen = false;
String[] itemDesc;
int position;
int size;
int maxLabelWidth = 100;
int minLabelWidth = 20;
final Handler timeHandler = new Handler();
Runnable toggleTimer;
public CircularLabeledImageView(Context context) {
super(context);
//EDIT Methhod called
initView(context);
}
public CircularLabeledImageView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public CircularLabeledImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context){
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.expandabletextimageview, this);
headerView = (ImageView) this.findViewById(R.id.header);
labelView = (TextView) this.findViewById(R.id.label);
labelView.setBackgroundResource(R.color.backgroundMenuContents);
headerView.setOnClickListener(this);
itemDesc = new String[]{"Item A","Item B", "Item C","Quantos itens"};
size = itemDesc.length;
toggleTimer = new Runnable() {
#Override
public void run() {
toggle();
}
};
this.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (isOpen) {
toggle();
}
}
});
}
}
The code for the custom ViewGroup
public class RingListMenu extends ViewGroup implements View.OnClickListener {
boolean isOpen = true;
int headerSize= 90;
int childSize= 80;
int radiusInit = 150;
int childInitSize = 80;
int radius = 150;
int padding;
DPoint center = new DPoint();
float startingAngle= 2;
DPoint click0;
DPoint clickIni;
DPoint clickFinal;
final static float SENSIBILITY = 10f;
final static float FRICTION = 0.00001f;
final static float MAXVELOCITY = 0.06f;
final static long TOGGLE_DURATION = 300;
private VelocityTracker vTracker = null;
boolean isScrolling;
ImageView circleView;
OnItemClickListener listener = null;
public RingListMenu(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
TypedArray at = context.obtainStyledAttributes(attrs,R.styleable.RingListMenu);
childInitSize = childSize = at.getDimensionPixelSize(R.styleable.RingListMenu_childSize, 0);
radiusInit = radius = at.getDimensionPixelSize(R.styleable.RingListMenu_circleRadius, 0);
headerSize = at.getDimensionPixelSize(R.styleable.RingListMenu_headerSize, 0);
padding = at.getDimensionPixelSize(R.styleable.RingListMenu_padding, 0);
}
public RingListMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
TypedArray at = context.obtainStyledAttributes(attrs,R.styleable.RingListMenu);
childInitSize = childSize = at.getDimensionPixelSize(R.styleable.RingListMenu_childSize, 0);
radiusInit = radius = at.getDimensionPixelSize(R.styleable.RingListMenu_circleRadius, 0);
headerSize = at.getDimensionPixelSize(R.styleable.RingListMenu_headerSize, 0);
padding = at.getDimensionPixelSize(R.styleable.RingListMenu_padding, 0);
}
public RingListMenu(Context context, AttributeSet attrs) {
super(context, attrs);
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
TypedArray at = context.obtainStyledAttributes(attrs, R.styleable.RingListMenu);
childInitSize = childSize = at.getDimensionPixelSize(R.styleable.RingListMenu_childSize, 0);
radiusInit = radius = at.getDimensionPixelSize(R.styleable.RingListMenu_circleRadius, 0);
headerSize = at.getDimensionPixelSize(R.styleable.RingListMenu_headerSize, 0);
padding = at.getDimensionPixelSize(R.styleable.RingListMenu_padding, 0);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.d("RingList", "Calling Ring list onLayout" + childSize + " " + radius + " " + headerSize);
float angle = (float) (2*Math.PI)/(getChildCount()-1);
center.x = padding+headerSize/2;
center.y = padding+headerSize/2;
float childX;
float childY;
//radius = (float) (getChildCount()*(minSpacing+2*childSize)/(2*Math.PI));
for (int i = 1; i < getChildCount(); i++) {
View child = getChildAt(i);
childX = (float) (center.x + radius * Math.cos(startingAngle + i * angle));
childY = (float) (center.y + radius * Math.sin(startingAngle + i * angle));
child.layout((int) (childX - childSize / 2), (int) (childY - childSize / 2),
(int) (childX + childSize / 2), (int) (childY + childSize / 2));
}
View header = getChildAt(0);
header.setX(padding);
header.setY(padding);
header.layout(padding, padding, padding + headerSize, padding + headerSize);
}
#Override
public void addView(View child) {
child.setTag(getChildCount());
super.addView(child);
child.setOnClickListener(this);
}
}
And finally, the declaration part:
RingListMenu ring = (RingListMenu) findViewById(R.id.ring);
CircularLabeledImageView ViewA = new CircularLabeledImageView(this);
ring.addView(ViewA);
The custom View in my custom ViewGroup refuses to show the drawable given to it by calling setImageResource(). It is laid out as I need it, however, as you can see in this screenshot, it's empty:
Also, it won't react on an onClick event.
Here's the java code for my Activity
public class MainActivity extends Activity {
public static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BattleShipsGameBoard gb = (BattleShipsGameBoard) findViewById(R.id.gameboard);
Tile tile = new Tile(this);
tile.setImageResource(R.drawable.tile_hit);
tile.setGameObjectType(BattleShipsGameBoard.LayoutParams.LAYOUT_TYPE_TILE);
tile.setPosition(new Point(50, 50));
tile.setWidth(90);
tile.setHeight(90);
gb.addView(tile);
}
}
and my custom view
public class Tile extends ImageView {
#SuppressWarnings("unused")
private static final String TAG = "Tile";
public int tag;
public int gameObjectType;
public Point position = new Point(0, 0);
public int mWidth = 1;
public int mHeight = 1;
public boolean isSelected = false;
public Tile(Context context) {
super(context);
setLayoutParams(new BattleShipsGameBoard.LayoutParams(
BattleShipsGameBoard.LayoutParams.WRAP_CONTENT,
BattleShipsGameBoard.LayoutParams.WRAP_CONTENT));
}
public Tile(Context context, AttributeSet attrs) {
super(context, attrs);
}
public Tile(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void confirmChangesInLayout() {
BattleShipsGameBoard.LayoutParams lp = (BattleShipsGameBoard.LayoutParams) this
.getLayoutParams();
lp.setPosition(this.position);
lp.setWidth(this.mWidth);
lp.setHeight(this.mHeight);
setLayoutParams(lp);
invalidate();
requestLayout();
}
//... getters and setters, the setters all call confirmChangesInLayout()
}
my simple custom ViewGroup:
public class BattleShipsGameBoard extends ViewGroup {
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
public LayoutParams(int width, int height) {
super(width, height);
}
public Point position = new Point(0, 0);
public int type = 0;
public int height = 0;
public int width = 0;
//getters and setters
}
public BattleShipsGameBoard(Context context) {
super(context);
}
public BattleShipsGameBoard(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BattleShipsGameBoard(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private float unitWidth;
private float unitHeight;
private int parentWidth;
private int parentHeight;
/**
* count of units the screen estate is divided by
*/
public static int unitCount = 100;
/**
* Rectangle in which the size of a child is temporarily stored
*/
private Rect mTmpChildRect = new Rect();
/**
* lays out children
*/
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Log.d(TAG, "-------------STARTING LAYOUT, " + getChildCount() + " children -------------");
int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
Point pos = lp.getPosition();
int height = lp.getHeight();
int width = lp.getWidth();
measureChild(child, parentWidth, parentHeight);
mTmpChildRect.left = (int) ((pos.x - (width / 2)) * unitWidth);
mTmpChildRect.right = (int) ((pos.x + (width / 2)) * unitWidth);
mTmpChildRect.top = (int) ((pos.y + (height / 2)) * unitHeight);
mTmpChildRect.bottom = (int) ((pos.y - (height / 2)) * unitHeight);
child.layout(mTmpChildRect.left, mTmpChildRect.top, mTmpChildRect.right, mTmpChildRect.bottom);
Log.d(TAG,
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
parentHeight = MeasureSpec.getSize(heightMeasureSpec);
parentWidth = MeasureSpec.getSize(widthMeasureSpec);
unitHeight = parentHeight / unitCount;
unitWidth = parentWidth / unitCount;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.measure(widthMeasureSpec, heightMeasureSpec);
}
}
setMeasuredDimension(parentWidth, parentHeight);
}
/**
* Any layout manager that doesn't scroll will want this.
*/
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
}
I just found the problem.
In the onLayout() method I mixed up mTmpChildRect.top and mTmpChildRect.bottom which is why it looked like it was laid out correctly but nothing could be drawn.
i initialized Listview through XML :
<com.example.app.ListViewManage
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="45dp"
/>
and i couldn't manage initializing the list inside a class is there a way doing that ?
class code: im trying to set with init() function, and how could i pass values from another class if this class is passed to the XML?
public class ListViewManage extends ListView{
int HEADER_HEIGHT = 45;
int HeaderID = 0;
Context context = null;
int HeightInPixels = 0;
int WidthInPixels = 0;
float alphaScale = 0;
float PrevAlpha = 0;
public ListViewManage(Context context) {
super(context);
init(context);
}
public ListViewManage(Context context,AttributeSet attrs){
super(context, attrs);
}
public ListViewManage(Context context,AttributeSet attrs,int defStyle){
super(context, attrs,defStyle);
}
public void init(Context context){
this.context = context;
DisplayMetrics dm = context.getResources().getDisplayMetrics();
this.HeightInPixels = dm.heightPixels;
this.WidthInPixels = dm.widthPixels;
this.alphaScale = this.HEADER_HEIGHT/this.HeightInPixels;
FrameLayout.LayoutParams fl=(FrameLayout.LayoutParams)getLayoutParams();
fl.topMargin=HEADER_HEIGHT;
setLayoutParams(fl);
ArrayAdapter<YTFileDownload> ListAdapter = new ArrayAdapter<YTFileDownload>(context,R.layout.download_list_view,R.id.Title,YTDownloadsManage.Downloads){
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
ProgressBar bar =(ProgressBar)v.findViewById(R.id.Process);
bar.setProgress(0);
TextView tv = (TextView)v.findViewById(R.id.Title);
tv.setText(YTDownloadsManage.Downloads.get(position).getVideoID());
TextView tv2 = (TextView)v.findViewById(R.id.Speed);
tv2.setText("0MB");
return v;
}
};
LayoutInflater li=LayoutInflater.from(context);
this.setAdapter(ListAdapter);
}
}
ListViewManage mlv = (ListViewManage) findViewById(R.id.list);
mlv.setAdapter(adapter);
In your getView() method, i think you should missed:
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.custom_listview_item, null);
adapter.notifyDataSetChanged();
I use a ViewGroup as a container to place multiple instances of a smaller-sized icon image at arbitrary locations. When the icons are placed near the bottom or right edge of the container, they are automatically scaled to fit within the bounds of the ViewGroup. Why does this happen, and how do I prevent it? I set the clipChildren attribute on the ViewGroup to FALSE to see if that worked, but it doesn't.
The ViewGroup is added dynamically. m_iconContainer is the ViewGroup which parents the icons.
m_outerContainer = (ViewGroup) v.findViewById( R.id.outer );
m_iconContainer = new ScalingFrameLayout( getActivity() );
m_outerContainer.addView( m_iconContainer );
Icons are added in a straightforward manner:
PinImage p = new PinImage( getActivity() );
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) p.getLayoutParams();
params.leftMargin = pt.x - PIN_IMAGE_XOFFSET;
params.topMargin = pt.y - PIN_IMAGE_YOFFSET;
m_iconContainer.addView( p );
public class ScalingFrameLayout extends FrameLayout {
private float scale = 1;
public ScalingFrameLayout(Context context) {
super(context);
setWillNotDraw(false);
setClipChildren(false);
}
public void setScale(float factor) {
scale = factor;
invalidate();
}
public float getScale() {
return scale;
}
#Override
public void onDraw(Canvas canvas) {
canvas.scale(scale, scale);
super.onDraw(canvas);
}
}
protected class PinImage extends ImageView {
public PinImage( Context c ) {
super( c );
setLayoutParams( new FrameLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT ));
setImageResource( R.drawable.droppin );
this.setOnClickListener( new OnClickListener() {
public void onClick( View v ) {
onCommentPinTouched( v );
}
});
}
}