I am adding ImageView dynamically inside a RelativeLayout programmatically but I also need to attach remove icon/button with onClick handler with those dynamic ImageViews. So that if I click on any of the delete icon related to that dynamic image view will be deleted.
Here is my code where I am adding dynamic image views inside the layout:
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
final ImageView iv = new ImageView(this);
iv.setId(id);
iv.setPadding(2, 2, 2, 2);
iv.setImageBitmap(BitmapFactory.decodeResource(
getResources(), (int)iconTable[id]));
iv.setScaleType(ImageView.ScaleType.MATRIX);
iv.setLayoutParams(lp);
rl.addView(iv);
I'd recommend to create a custom component. Something like this:
public class DeletableImageView extends LinearLayout {
private ImageView mImage;
private Button mButton;
DeletableImageListener mListener
public DeletableImageView(Context context) {
super(context);
init(context);
}
public DeletableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DeletableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setOrientation(LinearLayout.VERTICAL);
inflate(context, R.layout.deletable_image, this);
initViews();
}
private void initViews() {
mImage= (ImageView) findViewById(R.id.image);
mButton= (Button) findViewById(R.id.delete_button);
mButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
if (mListener != null) {
mListener.deleteMe(DeletableImageView.this);
}
}
}
}
public void setListener(DeleteableImageListener listener) {
mListener = listener;
}
public interface DeletableImageListener {
void deleteMe(DeletableImageView me);
}
public void setImage(Drawable drawable) {
mImage.setBackground(drawable);
}
}
R.layout.deletable_imageis a normal xml-layout with <merge> as root element (since the DeletableImageView already is a LinearLayout. Within the merge-Tag you have the ImageView and the Button.
<merge xmlns="...">
<ImageView android:id="#+id/image" .../>
<Button android:id="#+id/delete_button" .../>
</merge>
In your code you don't add an ImageView, but your custom component and set the Listener as callback, so you can remove the custom component again.
RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
final DeletableImageView div = new DeletableImageView(this);
div.setImage(...); // add this method to DeletableImageView
div.setListener(this);
// either implement these in your custom component or directly set it in the <ImageView> in R.layout.deletable_image
div.setScaleType(...);
div.setPadding(2, 2, 2, 2);
rl.addView(div);
The last step is to implement deleteMe(DeletableImageView me). You have to hold a reference to your RelativeLayout and it should work by just calling rl.removeView(me);
Related
Is it possible to create another control inside a custom View class.
I want to add an image and a progress bar inside a custom class.
There is no addView method in View class.
Is ViewGroup is the only option?
When creating a custom View class you can inflate a layout. In the custom View classes constructor just call inflate(context, R.layout.custom_layout, this); and in custom_layout put a ProgressBar and an ImageView. When doing this have the custom View extend the same View class that is the root of custom_layout Eg if the root of custom_layout is a LinearLayout, extend LinearLayout.
public class CustomClass extends FrameLayout {
Context c;
ProgressBar progressBar;
ImageView imageView;
public CustomClass(Context context) {
super(context);
loadControls(context);
}
public CustomClass(Context context, AttributeSet attrs) {
super(context, attrs);
loadControls(context);
}
public CustomClass(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
loadControls(context);
}
public void loadControls(Context context)
{
c = context;
progressBar = new ProgressBar(c, null, android.R.attr.progressBarStyleInverse);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.TOP | Gravity.LEFT);
imageView = new ImageView(c);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
//imageView.setBackgroundColor(color.darker_gray);
addView(imageView, params);
params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
addView(progressBar, params);
progressBar.setVisibility(View.VISIBLE);
}}
I want to place different custom view at a certain position that i set and it will always place on the top-left corners.
I have tried the method using
LayoutParams params = new LayoutParams(v1.getWidth(), v1.getHeight());
params.leftMargin = 100;
params.topMargin = 100;
mView.addView(v1,params);
In this way, the left top corner is disappeared...
Further, can I set a rotation on the inserted custom view as well?
please give me some advice to deal with this question
Here is the detail code,
MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw_main);
myDraw = (RelativeLayout) findViewById(R.id.myDraw);
Button btnAddRect = (Button) findViewById(R.id.btnAdd);
btnAddRect.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v1 = vi.inflate(R.layout.drawbox, null);
mfView = (SingleFingerView) v1.findViewById(R.id.draw);
myDraw.addView(v1);
// myDraw.addView(v1, params);
myDraw.invalidate();
}
});
}
CustomView
public class SingleFingerView extends LinearLayout{
public SingleFingerView(Context context) { this(context, null, 0); }
public SingleFingerView(Context context, AttributeSet attrs) { this(context, attrs, 0); }
public SingleFingerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.parseAttr(context, attrs);
View mRoot = View.inflate(context, R.layout.test_image_view, null);
mView = (ImageView) mRoot.findViewById(R.id.view);
mPushView = (ImageView) mRoot.findViewById(R.id.push_view);
mPush1DView = (ImageView) mRoot.findViewById(R.id.push1d_view);
mFirmView = (ImageView) mRoot.findViewById(R.id.firm_view);
mRemoveView = (ImageView) mRoot.findViewById(R.id.remove_view);
addView(mRoot, -1, -1);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setParamsForView(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
}
xml of Main
<RelativeLayout
android:id="#+id/myDraw"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerInside"
android:src="#drawable/bg"
/>
Try this, no need to make things so complicated.
That should add your custom view to your relativeLayout with the width height you want and a left and top margins of 100px.
public void onClick(View v) {
mfView = new SingleFingerView(MainActivity.this);
RelativeLayout.LayoutParams prms = new RelativeLayout.LayoutParams(width,height);
prms.setMargins(100,100,0,0);
myDraw.addView(mfView,prms);
}
Hope this helps.
I was creating my textview which use as a header in my MainActivity file and everything was okay until I thought I'd better move the code to another class.
While it works and displays the text however when I try to animate it it doesn't work.
The code I was using is in the init() method.
The code is very simple and I'm pasting it here:
public class TextViewHeader extends TextView {
private static final String TAG = "TextViewHeader".toUpperCase();
private Context context;
private FrameLayout frameLayoutWhiteTowerContainer;
private String text;
private int whiteTowerContainerHeight;
private int tower_height;
public TextViewHeader(Context context) {
super(context);
}
public TextViewHeader(Context context, String text, FrameLayout frameLayoutWhiteTowerContainer,
int whiteTowerContainerHeight, int tower_height) {
super(context);
this.context = context;
this.text = text;
this.frameLayoutWhiteTowerContainer = frameLayoutWhiteTowerContainer;
this.whiteTowerContainerHeight = whiteTowerContainerHeight;
this.tower_height = tower_height;
init();
}
public TextViewHeader(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init() {
TextView textView = new TextView(context);
textView.setText(text);
textView.setTextSize(25);
textView.setTextColor(Color.parseColor("#FF545454"));
Typeface typefaceCondensed = Typeface.create("sans-serif-condensed", Typeface.BOLD);
textView.setTypeface(typefaceCondensed);
FrameLayout.LayoutParams tv_header_params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
int topMargin = whiteTowerContainerHeight / 2 - tower_height / 2 - 100;
tv_header_params.topMargin = topMargin;
tv_header_params.gravity = Gravity.CENTER_HORIZONTAL;
textView.setLayoutParams(tv_header_params);
frameLayoutWhiteTowerContainer.addView(textView, tv_header_params);
}
}
The code in MainActivity is :
tvHeader = new TextViewHeader(MainActivity.this, "TOWER", flWhiteTowerContainer,
whiteTowerContainerHeight, tower_height ); // create inside onCreate method
tvHeader.animate().y(515).setDuration(1500).start(); //and the animation happens later onMapReady
You are starting an animation before the TextViewHeader is laid out.
Try:
tvHeader = new TextViewHeader(MainActivity.this, "TOWER", flWhiteTowerContainer,
whiteTowerContainerHeight, tower_height );
tvHeader.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
// Layout complete but not drawn yet
tvHeader.getViewTreeObserver().removeOnPreDrawListener(this);
tvHeader.animate().y(515).setDuration(1500).start();
return false;
}
});
The problem is that I'm implementing the TextView but I don't use it. Instead I just create another TextView in the class and I use this instead of my class.
In other words the code :
TextView textView = new TextView(context);
shouldn't exist and just use this to setText, setTextSize, color, etc.
this.setText(text);
this.setTextSize(25);
this.setTextColor(Color.parseColor("#FF545454"));
I am trying to build a custom view in Android that shows an image, and some text fields (non-editable).
I started by extending the RelativeLayout class for my custom view.
In the constructor of my custom view I created an ImageView and a TextView, and added them to the layout.
The TextView is loaded immediately, but the ImageView is loaded on a different thread and the bitmap is populated through a handler.
Once the bitmap is loaded, the ImageView is overlapping the TextView. The TextView is supposed to be on the "right-of" the ImageView, but this adjustment is not happening automatically.
I tried using customView.invalidate(), but that did not help.
This problem is not there when the same components are declared via XML.
Any help in resolving would be appreciated. Thanks
public class MyView extends RelativeLayout {
private TextView productName;
private ImageView productImage;
public MyView(Context context) {
super(context);
initHandler();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initHandler();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initHandler();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
initHandler();
}
private void initHandler() {
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// implement logic to show content here
productName.setText(currentProduct.getTitle());
productImage.setImageBitmap(currentProduct.getImageBitmap());
MyView.this.invalidate();
}
};
productImage = new ImageView(getContext());
RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layout.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
layout.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
productImage.setLayoutParams(layout);
//keep the textview to right of imageview
productName = new TextView(getContext());
layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
layout.addRule(RelativeLayout.RIGHT_OF, productImage.getId());
layout.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
productName.setLayoutParams(layout);
productName.setTextColor(Color.parseColor("#ffffff"));
this.addView(productImage);
this.addView(productName);
//logic to load content on a new thread goes here
}
}
XML in which I included the custom view:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mycompany.MyView
android:background="#android:color/black"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
you need add an id to your View in xml
<com.mycompany.MyView
android:id="#+id/myView"
android:background="#android:color/black"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
and in your java initilize it like
ImageView im = (ImageView)findViewById(R.id.myView);
try that
I would like to inflate a LinearLayout with multiple instances of another LinearLayout. How can I do that? My problem is that I seem to always use the same instance and hence add that instance over and over again.
In short: What I need is a way to add new instances of a LinearLayout child to another LinearLayout parent.
Here is what I have done so far:
private void setupContainers() {
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService(MainActivity.LAYOUT_INFLATER_SERVICE);
LinearLayout parentContainer = (LinearLayout)this.findViewById(R.id.parent_container);
for (int i = 0; i < someNumber; i++) {
LinearLayout childContainer = (LinearLayout) layoutInflater.inflate(R.layout.child_container, null);
parentContainer.addView(childContainer);
}
}
Try this:
for (int i = 0; i < someNumber; i++) {
LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); // or any other layout params that suit your needs
LinearLayout childContainer = new LinearLayout(this);
parentLayout.addView(childContainer, params)
}
EDIT
Considering you need to use the content from XML, you'll need to create a custom class that extends LinearLayout and initialize in there all its properties. Something like:
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MyLinearLayout(Context context) {
super(context);
init(context);
}
private void init(Context context) {
inflate(context, R.id.R.layout.child_container, this);
// setup all your Views from here with calls to getViewById(...);
}
}
Also, since your custom LieanrLayout extends from LinearLayout you can optimize the xml by replacing the root <LinearLayout> element with <merge>. Here is a short documentation and an SO link. So the for loop becomes:
for (int i = 0; i < someNumber; i++) {
LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); // or any other layout params that suit your needs
LinearLayout childContainer = new MyLinearLayout(this);
parentLayout.addView(childContainer, params); // feel free to add or not the LayoutParams object
}