5

I have a class that extends view, that defines a custom drawing (a resistor). I want to click a button and add that view to the main layout. so that I see the resistor, and if I click again it will add another resistor and so on. but I don't know the best way to approach this problem. I have looked at a lot of questions referring to layoutinflater, but none of them inflate a custom view class (maybe I am looking for the wrong thing), is always a xml file. So my question is: How can I add multiple ResistorViews to my layout, so that the user can interface (move, delete,highlight, etc) with them?

This is what I have tried:

Activity Class:

public class CircuitSolverActivity extends Activity {       

@Override    
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final Button bAddResistor = (Button) findViewById(R.id.bAdd);        
    final LinearLayout mLayout = (LinearLayout)findViewById(R.layout.main);
    final ResistorView mResistor = new ResistorView(this, 100, 100);
    bAddResistor.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {               

            mLayout.addView(mResistor);                 

        }
    });
  }    

}

ResistorView class:

public class ResistorView extends View{

    private Path mSymbol;
    private Paint mPaint;

    int mX, mY;

    //...Override Constructors...    
    public ResistorView(Context context, AttributeSet attrs) {
        super(context, attrs);        
        init();
    }

    public ResistorView(Context context, int x, int y){
        super(context);     
        mX = x;
        mY = y;
        init();
    }

    private void init() {

        mSymbol = new Path();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);      
        mPaint.setStrokeWidth(2);
        mPaint.setColor(-7829368);  

        mPaint.setStyle(Paint.Style.STROKE);       

        mSymbol.moveTo(0.0F, 0.0F);
        mSymbol.lineTo(0.0F, 50.0F);
        mSymbol.lineTo(16.666666F, 58.333332F);
        mSymbol.lineTo(-16.666666F, 75.0F);
        mSymbol.lineTo(16.666666F, 91.666664F);
        mSymbol.lineTo(-16.666666F, 108.33333F);
        mSymbol.lineTo(16.666666F, 124.99999F);
        mSymbol.lineTo(-16.666666F, 141.66666F);
        mSymbol.lineTo(0.0F, 150.0F);
        mSymbol.lineTo(0.0F, 200.0F);
        mSymbol.offset(mX, mY);

    }

    @Override
    protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);
    canvas.drawPath(mSymbol, mPaint);       
  }
}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"        
    android:orientation="vertical"
    android:id="@+id/main">

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

    <Button
        android:id="@+id/bAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add RES" />


</LinearLayout>

Thanks.

EDIT: SOLVED *Thanks again for the help.*

0gravity
  • 2,682
  • 4
  • 24
  • 33

3 Answers3

4

Inflating (in terms of Android views) is strictly for XML. If you're dynamically creating and adding a view object in code, then that's not inflating. What you're doing in your code right now is pretty close. The only problem being that you instantiate the view once, whereas it sounds like you want to add a new one every time you click. Try moving the instantiation into the click handler:

public class CircuitSolverActivity extends Activity {       

@Override    
public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final Button bAddResistor = (Button) findViewById(R.id.bAdd);        
    final LinearLayout mLayout = (LinearLayout)findViewById(R.id.main);
    bAddResistor.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {               
            final ResistorView mResistor = new ResistorView(CircuitSolverActivity.this, 100, 100);
            mLayout.addView(mResistor);                 
        }
    });
  }    
}
kabuko
  • 36,028
  • 10
  • 80
  • 93
  • Thanks for that answer, I have tried what you suggested, but when I put instantiate line, I cant use the keyword "this" to get the context. So instead of "this" what else can I do to get the context? – 0gravity Jul 09 '12 at 04:01
  • Ok, so I have used getBaseContext() and the code that Kabuko suggested but I get a java.lang.NullPointerException error on LogCat. This happens when I click the button. – 0gravity Jul 09 '12 at 04:07
  • use CircuitSolverActivity.this in place of this. – Zaz Gmy Jul 09 '12 at 04:55
  • Oops, yeah you can't just use `this`. You don't have to use `getBaseContext()` either. You can use `CircuitSolverActivity.this`. Also, you need to pass the layout to `setContentView`, but the id of the root layout view to `findViewById`. These are different. I'll update my answer to reflect this. – kabuko Jul 09 '12 at 05:18
  • I tried your code, but now the resistor is not showing up...mLayout is not null and is not giving me an error, but is not displaying the resistor. – 0gravity Jul 09 '12 at 05:38
  • @kabuko by "Inflating (in terms of Android views) is strictly for XML. If you're dynamically creating and adding a view object in code, then that's not inflating." what about when inflating a view from "template" layout (ie, inflater.inflate(R.layout.templated_text_view1, this, null)) ? – samus Jan 09 '13 at 20:24
  • @SamusArin that "template" layout is inflated from XML then. See the [documentation for inflate](http://developer.android.com/reference/android/view/LayoutInflater.html#inflate%28int,%20android.view.ViewGroup,%20boolean%29): "Inflate a new view hierarchy from the specified **xml** resource." – kabuko Jan 09 '13 at 20:30
  • @kabuko ... oh, I was thinking that you were suggesting that a dynamically created object (in code) can **only** be done by building it yourself (adding views with AddView). I misinterpreted... – samus Jan 11 '13 at 15:46
2

Save the context as a private instance variable like private Context context; and Init the context like context=this; in the constructor of the activity. The add the custom view using the context Variable in the onclick callback method

bAddResistor.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {               
     final ResistorView resistor = new ResistorView(context, 100, 100);
     mLayout.addView(resistor);
    }
});
Gautam
  • 7,868
  • 12
  • 64
  • 105
0

You can refer to "this" of an external class by adding its name. Suppose you have class A inside which you define a class B. Inside B, "this" refers to B, but you can also type "A.this" and get A's this.

Hope this helps.

Shachar

Shachar Shemesh
  • 8,193
  • 6
  • 25
  • 57