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.
Related
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);
I want to create a custom view which should be added in another custom view.
The second view will be a container, so it should be able to contain the first view as its child.
For creating this views I am extending ViewGroup & LinearLayout classes.
Child view class is NodeView
public class NodeView extends LinearLayout
{
private final static String TAG = "NodeView";
private ImageView ivTop;
private ImageView ivBottom;
private Context myContext;
public NodeView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.myContext = context;
setOrientation(LinearLayout.VERTICAL);
setGravity(Gravity.CENTER);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_test_multi, this, true);
ivTop = (ImageView) getChildAt(0);
ivBottom = (ImageView) getChildAt(2);
ivTop.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Toast.makeText(myContext, "Top Clicked", Toast.LENGTH_SHORT).show();
}
});
ivBottom.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Toast.makeText(myContext, "Bottom Clicked", Toast.LENGTH_SHORT).show();
}
});
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
}
public NodeView(Context context)
{
this(context, null);
}
}
& the container class is TreeViewGroup
public class TreeViewGroup extends ViewGroup
{
private static final String TAG = "CustomTreeNodeView";
NodeView nodeView;
public TreeViewGroup(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
nodeView = new NodeView(getContext());
addView(nodeView);
}
public TreeViewGroup(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public TreeViewGroup(Context context)
{
this(context, null, 0);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
}
}
& xml layout for node view is view_test_multi.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:src="#drawable/point_grey" />
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:src="#drawable/point_red" />
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_centerVertical="true"
android:src="#drawable/point_grey" />
</merge>
My activity's layout is activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.ab1209.testcustom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.ab1209.testcustom.view.TreeViewGroup
android:id="#+id/activity_main_custom_tree_node_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
MainActivity class is
**public class MainActivity extends Activity
{
TreeViewGroup treeNodeView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
treeNodeView = (TreeViewGroup) findViewById(R.id.activity_main_custom_tree_node_view);
}
}**
When I run the app I don't see the NodeView added in main View. Am I doing the right thing if not please tell me how can I make it working?
To create a custom ViewGroup, the only method you need to override is
onLayout. The onLayout is triggered after the ViewGroup itself has
finished laying itself out inside its own container ViewGroup and is
now responsible for laying out its children. It should call the layout
method on all of its children to now position and size them (the left
and top parameters will determine the child view’s x and y and the
right and bottom will determine its width (right – left) and height
(top-bottom).
So your TreeViewGroup code will look like :
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) child
.getLayoutParams();
int childLeft = 0;
int childTop = 0;
child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(),
childTop + child.getMeasuredHeight());
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
measureChildren(widthMeasureSpec, heightMeasureSpec);
int measuredWidth = 200; // Calculate the height
int measuredHeight = 200; // Calculate the width
setMeasuredDimension(measuredWidth, measuredHeight);
}
Refer this link http://arpitonline.com/2012/07/01/creating-custom-layouts-for-android/
What I am trying to achieve:
measure a container View in my layout, mainContainer, that is defined in the XML
pass the mainContainer's width and height to a different custom View before onDraw() is called
I want to pass the width and height so the custom View knows where to draw canvas.drawBitmap using coordinates
The custom view will be programmatically created from code
How can I pass the measured int width and int height to my custom View before onDraw() is called?
Custom View
public class AvatarView extends ImageView {
private Bitmap body;
private Bitmap hat;
public AvatarView(Context context) {
super(context);
init();
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
body = BitmapFactory.decodeResource(getResources(), R.drawable.battle_run_char);
hat = BitmapFactory.decodeResource(getResources(), R.drawable.red_cartoon_hat);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(body, x, y, null);
canvas.drawBitmap(hat, x, y, null);
}
}
Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_customize_avatar, container, false);
final RelativeLayout mainContainer = (RelativeLayout) view.findViewById(R.id.main_container);
TwoWayView inventoryList = (TwoWayView) view.findViewById(R.id.inventory);
inventoryList.setAdapter(null);
inventoryList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
}
});
mainContainer.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
// Retrieve the width and height
containerWidth = mainContainer.getWidth();
containerHeight = mainContainer.getHeight();
// Remove global listener
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN)
mainContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
else
mainContainer.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
return view;
}
XML
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clickable="true"
android:background="#fff" >
<com.walintukai.lfdate.CustomTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:textStyle="bold"
android:textColor="#fff"
android:textSize="20sp"
android:textAllCaps="true"
android:text="#string/customize_avatar"
android:background="#009BFF" />
<RelativeLayout
android:id="#+id/main_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<org.lucasr.twowayview.TwoWayView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/inventory"
style="#style/HorizontalListView"
android:layout_width="match_parent"
android:layout_height="80dp"
android:drawSelectorOnTop="false"
android:background="#f3f3f3" />
</LinearLayout>
What you need to do is add a flag inside your AvatarView that checks if are you going to render this or not in your onDraw method.
sample:
public class AvatarView extends ImageView {
private Bitmap body;
private Bitmap hat;
private int containerHeight;
private int containerWidth;
private boolean isRender = false;
public AvatarView(Context context) {
super(context);
init();
}
public AvatarView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AvatarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setMeasure(int containerWidth, int containerHeight )
{
this.containerHeight = containerHeight;
this.containerWidth = containerWidth;
}
private void init() {
body = BitmapFactory.decodeResource(getResources(), R.drawable.battle_run_char);
hat = BitmapFactory.decodeResource(getResources(), R.drawable.red_cartoon_hat);
}
public void setRender(boolean render)
{
isRender = render;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(isRender )
{
canvas.drawBitmap(body, x, y, null);
canvas.drawBitmap(hat, x, y, null);
}
}
}
Now it wont render when you dont call setRender and set it to true. And just call setMeasure to pass the value.
First you need to call setMeasure and after you set the measure you then call setRender(true) and call invalidate() to call the onDraw method to render the images
I have a custom view (a class extending View) that I'd like to add as a header of List View. Here's the code snippet:
public class MyActivity extends RoboListActivity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View header = getLayoutInflater().inflate(R.layout.myactivity_apps_header, null);
getListView().addHeaderView(header);
...more code
}
But, I can't see anything. But, when I tried to add a non-custom view, it works. Am I missing something, please guide
Providing Complete Source Code
Custom View
public class SpaceCustomView extends View {
private Paint mPaint;
private Paint mTextPaint;
private final String mMessage = "Foo Bar";
private Rect mBounds;
public StorageSpaceCustomView(Context context) {
super(context);
initInput();
}
public StorageSpaceCustomView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
initInput();
}
public StorageSpaceCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initInput();
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
#Override
public void onDraw(android.graphics.Canvas canvas) {
canvas.drawRect(30, 30, 800, 80, mPaint);
canvas.drawText(mMessage, 30, 60, mTextPaint);
}
private void initInput() {
mBounds = new Rect();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mTextPaint = new Paint();
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextAlign(Paint.Align.LEFT);
mTextPaint.setTextSize(20);
mTextPaint.getTextBounds(mMessage, 0, mMessage.length(), mBounds);
}
}
Header Layout XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.mycompany.app.view.custom.SpaceCustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Activity Class
public class AppsActivity extends RoboListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//add header and footer views
View header = getLayoutInflater().inflate(R.layout.activity_apps_header, null);
getListView().addHeaderView(header);
View footer = getLayoutInflater().inflate(R.layout.activity_pps_footer, null);
getListView().addFooterView(footer);
List<AppInfo> applicationList = Mycatalog.getPromotions();
AppListAdapter adapter = new AppListAdapter(this, applicationList);
setListAdapter(adapter);
}
private class AppListAdapter extends ArrayAdapter<AppInfo> {
public AppListAdapter(Activity activity, List<AppInfo> apps) {
super(activity, android.R.layout.simple_list_item_1, apps);
}
#Override
public boolean isEmpty(){
return false;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// if we weren't given a view, inflate one
if (null == convertView) {
convertView = getLayoutInflater()
.inflate(R.layout.activity_uninstall_apps, null);
}
return convertView;
}
}
}
Conclusion: I can see the footer but not the header.
ListView shows headers and footers only when it's Adapter's isEmpty() returns false.
So try setting an adapter that does that...
I have a ListView in which there is a TextView and a custom view in which I am drawing a rectangle. I want a functionality that when a row of ListView is clicked, the rectangle should become bigger but other row's rectangle should remain in its previous shape.
So first I am increasing width and height of layout and then trying to increase the rectangle size after that but although my onDraw() method is called when I am clicking the listener but size of rectangle is not increasing.
Also my onDraw() method of DrawView is called infinitely even though I am clicking only once
Can anyone help me out.
DrawView.java, which is used for making making rectangle
public class DrawView extends View {
Paint paint = new Paint();
public int x=-1; // this variable will tell
public DrawView(Context context) {
this(context, null);
}
public DrawView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onDraw(Canvas canvas) {
paint.setStrokeWidth(10);
paint.setColor(Color.MAGENTA);
Log.e("Ronak","onDraw "+x);
canvas.drawRect(0, 0, 300, 200, paint );
if(x>=0) //this method is not called for first view but is called for onClickListener
{
increase(canvas);
}
}
private void increase(Canvas canvas) {
Log.e("Ronak","Increase");
canvas.drawRect(0, 0, 700, 800, paint );
}
}
My getView() function for custom ListView
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.news_list_item,null);
final LinearLayout layout = (LinearLayout)convertView.findViewById(R.id.mainLayout);
TextView t= (TextView)convertView.findViewById(R.id.textView1);
holder.textview = t;
holder.ll=layout;
final DrawView abc = (DrawView)convertView.findViewById(R.id.drawview);
holder.drawview=abc;
Log.e("Ronak","reached here3");
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.textview.setText(mData.get(position));
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(c, "Clicked on="+position, 2).show();
ViewHolder mH = (ViewHolder) v.getTag();
LinearLayout.LayoutParams pp = new LinearLayout.LayoutParams(500,400);
mH.ll.setLayoutParams(pp);
DrawView dd=mH.drawview;
dd.x=position;
dd.invalidate();
}
});
return convertView;
}
static class ViewHolder {
public DrawView drawview;
public TextView textview;
public LinearLayout ll;
}
and my layout file for each row of ListView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="2dp" >
<TextView
android:id="#+id/textView1"
android:layout_width="50dp"
android:layout_height="30dp"
android:text="Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<com.krish.horizontalscrollview.DrawView
android:id="#+id/drawview"
android:layout_width="150dp"
android:layout_height="100dp" >
</com.krish.horizontalscrollview.DrawView>
</LinearLayout>
My ListView class
public class CenterLockHorizontalScrollview extends HorizontalScrollView {
Context context;
int prevIndex = 0;
public CenterLockHorizontalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.setSmoothScrollingEnabled(true);
}
public void setAdapter(Context context, CustomListAdapter mAdapter) {
try {
fillViewWithAdapter(mAdapter);
} catch (ZeroChildException e) {
e.printStackTrace();
}
}
private void fillViewWithAdapter(CustomListAdapter mAdapter)
throws ZeroChildException {
if (getChildCount() == 0) {
throw new ZeroChildException(
"CenterLockHorizontalScrollView must have one child");
}
if (getChildCount() == 0 || mAdapter == null)
return;
ViewGroup parent = (ViewGroup) getChildAt(0);
//parent.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
parent.addView(mAdapter.getView(i, null, parent));
}
}
I suppose you store a String list in mData. Make a class with members mData and mIsSelected (boolean) and pass an object of this class in the adapter. In onClick() check whether the row is already selected, invert the value of mIsSelected and perform the required operation at end call notifyDataSetChanged()