I have created an external class, NotesView, which extends View for implementation in my MainActivity.
This View requires information passed from the MainActivity, so its constructor takes an ArrayList of Note objects.
public class NotesView extends View {
private ArrayList<Note> notes = new ArrayList<>();
public NotesView(Context context, ArrayList<Note> notes) {
super(context);
this.notes = notes;
}
In my MainActivity, I used the following code to display this view: (Trying to add a CustomView in the Design tab of the layout does not work as I cannot supply the ArrayList parameter)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
notesView = new NotesView(this, noteList);
setContentView(notesView);
}
Unfortunately, I am now not able to add any objects at all through the Design view of the layout, I assume this is because I have used setContentView. I do not wish to add all my components programmatically, is there a way around this?
Calling setContentView replaces the whole view for your layout. That means if you call setContentView twice, whatever was added to the screen from the first call is overridden and no longer accessible.
There are multiple answers to your question, here is a pragmatic one:
What is inside R.layout.activity_main? Let's assume there is a FrameLayout / LinearLayout / RelativeLayout with id root
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewGroup rootView = (ViewGroup) findViewById(R.id.root);
notesView = new NotesView(this, noteList);
rootView.addView(notesView);
}
Another choice, you could also take your custom view to have a setter if you wish:
public class NotesView extends View {
private final List<Note> notes = new ArrayList<>();
public NotesView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void replaceNotes(List<Note> notes) {
this.notes.clear();
this.notes.addAll(notes);
}
Then you can add this view in your XML file (R.layout.activity_main) and call the setter method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NotesView notesView = (NotesView) findViewById(R.id.notes);
notesView.replaceNotes(noteList);
}
You can add a setter function to your NotesView class:
public class NotesView extends View {
private ArrayList<Note> notes;
public NotesView(Context context) {
super(context);
}
public void setNotes(ArrayList<Note> notes) {
this.notes = notes;
}
}
And then set it in the main activity:
NotesView notesView = (NotesView) findViewById(R.id.yourNotesView);
notesView.setNotes(noteList);
By the way I recommend Butterknife to cast views in your layout without the verbose findViewByIds, declarations, onXListeners, etc.
Related
Background Info: I currently have an AppCompatActivity which is working. But right now, everything is in the onCreate method. I am concerned it is causing some little bugs I've been having lately with my PagerAdapter having java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! The bugs only happen when I switch activities back and forth very fast. I wonder if fixing this will fix the bug.
System requirements: Min SDK: 15, Target SDK: 23 (at the time of this writing, or whatever is most current)
Question: How do I move my user interface initialization code into the onCreateView method?
I am familiar with how to implement the onCreate method of android.support.v4.app.Fragment, like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_songdetail, container, false);
rootView.findViewById(R.id.info).setVisibility(View.INVISIBLE);
return rootView;
}
But there are no options like that for AppCompatActivity. These are my options, from the AppCompatActivity docs:
View onCreateView(String name, Context context, AttributeSet attrs)
View onCreateView(View parent, String name, Context context,
AttributeSet attrs)
Here is my code:
(I omitted the methods besides onCreate and onCreateView)
public class DealPage extends AppCompatActivity
{
private Deal deal;
private Poll poll;
private Video video;
#Override
protected void onCreate(Bundle savedInstanceState)
{
RealmDatabase.setRealmInstance(this);
//----------- UNPACK EXTRAS -----------
String date = getIntent().getExtras().getString(KeyStrings.EXTRA_DATE);
//---------------- PREREQUISITE INITIALIZATION ----------
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_deal_page);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_with_spinner);
setSupportActionBar(toolbar);
//------------ Enable "UP" navigation ---------------
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getDataFromDatabase(date);
//----------------- THEMES AND COLORS ------------------
//Set up colors
final int backgroundColor = this.deal.getTheme().getBackgroundColor().getColor();
final int accentColor = this.deal.getTheme().getAccentColor().getColor();
String themeForeground = this.deal.getTheme().getForeground();
final int foreground = generateForegroundColor(themeForeground);
final String foregroundWebView = generateForegroundWebViewString(themeForeground); // This is necessary because HTML does not have an alpha channel.
//Set toolbar colors
toolbar.setBackgroundColor(accentColor);
toolbar.setTitleTextColor(backgroundColor);
//Set Page Background Color
RelativeLayout dealPageBackground = (RelativeLayout) findViewById(R.id.deal_page_background);
dealPageBackground.setBackgroundColor(backgroundColor);
//----------- INITIALIZE THE ACTUAL DEAL PAGE STUFF ----------------
//Title
TextView title = (TextView) findViewById(R.id.title);
title.setText(this.deal.getTitle());
title.setTextColor(foreground);
//Price
TextView price = (TextView) findViewById(R.id.price);
NumberFormat fmt = NumberFormat.getCurrencyInstance();
price.setText(fmt.format(this.deal.getItems().first().getPrice()));
price.setTextColor(foreground);
//ViewInBrowser
setUpViewInBrowserButton(backgroundColor, accentColor);
AndDown andDown = new AndDown();
//Set up "linkColorHTML"
String linkColorHTML = generateLinkColorHTML(accentColor);
//Features
setUpFeaturesView(andDown, backgroundColor, linkColorHTML, foregroundWebView);
//More Specs button
setUpMoreSpecsButton(backgroundColor, foreground, (Spinner) findViewById(R.id.spinner));
//Story Title
TextView storyTitle = (TextView) findViewById(R.id.story_title);
storyTitle.setText(this.deal.getStory().getTitle());
storyTitle.setTextColor(accentColor);
//Story Body
setUpStoryBody(andDown, backgroundColor, linkColorHTML, foregroundWebView);
//Specs Title
TextView specsTitle = (TextView) findViewById(R.id.specs_title);
specsTitle.setText(this.deal.getTitle());
specsTitle.setTextColor(accentColor);
//Specs
setUpSpecificationsView(andDown, backgroundColor, linkColorHTML, foregroundWebView);
//Set up ViewPager
ViewPager viewPager = (ViewPager) findViewById(R.id.photos_view_pager);
viewPager.setAdapter(new PhotoPagerAdapter(this, this.deal.getPhotos()));
// Setup spinner
setUpSpinner(accentColor, backgroundColor, toolbar);
}
#Override
public View onCreateView(String name, Context context, AttributeSet attrs)
{
return super.onCreateView(name, context, attrs);
}
}
You must use a PlaceholderFragment.
Try this:
public class RestaurantListActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment(), "fragmentName").commit();
}
}
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {...}
I would like to get the Context of another activity where I created an object (an adapter that contains a list of objects I need to display in the second activity).
public class Activity1 extends Activity {
private Context context = this;
private GridView gridView;
private MyAdapter myAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myLayout);
myAdapter = new MyAdapter(context);
gridView = (GridView) findViewById(R.id.mylayout2);
gridView.setAdapter(myAdapter);
}
public class Activity2 extends Activity {
Context context = this;
private MyAdapter myAdapter;
private GridView gridView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout3);
//what I want to do
cardAdapter = new CardAdapter(manageCardContext); //I want this adapter to be the one in Activity1
gridView.setAdapter(myAdapter);
}
How can I do that ?
I created an adapter in Activity1 that contains a list of objects.
Only create an Adapter in the activity that will use the Adapter, and only use that Adapter in that activity.
With the adapter I can display the list of objects, but I need to display them in Activity2
Then move the adapter-creation code from Activity1 to Activity2. Or, if you need the same sort of adapter in both places, copy the code, or have both activities inherit from some base class that has the adapter-creation code.
In similar vein to CommonsWare suggestion, I defined a public adapter class outside the Activity, just in a class file (sorry, this is C# code, but you should get the point if you already written yer adapter)
CommonAdapter.java
public class CommonAdapter : ArrayAdapter<AttachmentDetails>
{
private readonly List<AttachmentDetails> _attachments;
public CommonAdapter( Context context, List<AttachmentDetails> attachments )
: base( context, 0, attachments )
{
_attachments = attachments;
}
public override View GetView( int position, View convertView, ViewGroup parent )
{
...
}
}
and the instantiate wherever i need it
_recordAttachmentsGrid.Adapter = new CommonAdapter(this.ApplicationContext, Model.Attachments);
This is what i am trying to do, this my main class file
private View TicTacStart;
//onCreate
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
TicTacStart = new Game(this);
//reference to base layout..
LinearLayout baseView = (LinearLayout)findViewById(R.id.baseView);
//I cant INFLATE THE VIEW SINCE I AM NOT USING XML AND RATHER USING ANOTHER CLASS GAME WHICH EXTENDS VIEW
LayoutInflater vi = (LayoutInflater)thisActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View thisScreensView = vi.inflate(TicTacStart, null);
//add the view to the base view...
baseView.addView(thisScreensView);
}
This is game class
public class Game extends View {
private Cell[][] singlesquare = null;
int x = 3;
int y = 3;
private int l;
private int a;
private boolean whatdrawn = false;
private int playerwin = 3;
private Paint caneta;
Data Data MORE classes
}
so basically what I want to do is add Game view class into baseview in my main class file. Is there someway i can make this work as i don't want to use xml's now.
Yuu can directly add GameView into baseview for ex:
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
TicTacStart = new Game(this);
//reference to base layout..
LinearLayout baseView = (LinearLayout)findViewById(R.id.baseView);
baseView.addView(TicTacStart );
}
I am trying to add Views to a custom ViewGroup. The ViewGroup gets drawn, but no Views that were added to it are visible. LineView's (which extends a View) onDraw() method does not get called. What am I doing wrong?
public class TestActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ShapeView shapeView = new ShapeView(this);
shapeView.setBackgroundColor(Color.RED);
drawContainer = (RelativeLayout)findViewById(R.id.draw_container);
drawContainer.addView(shapeView);
}
}
public class ShapeView extends ViewGroup {
private LineView mLineView;
public ShapeView (Context context) {
super(context);
RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(200, 200);
this.setLayoutParams(p);
mLineView = new LineView(context);
this.addView(mLineView);
}
}
I maybe wrong but should you not be adding the shapeView to your layout "main"? What is drawContainer? I can't see it being instantiated and not in the docs. I assume main contains a relative/linear layout.
Access it by:
RelativeLayout rel = (RelativeLayout) findViewById(R.id.container);
(where the id is changed to match your id)
then:
rel.addView(shapeView);
I am having a class that extends View. I have another class that extends activity and I want to add the first class to be loaded inside the activity class.
I tried the following code
package Test2.pack;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
public class Test2 extends Activity {
/** Called when the activity is first created. */
static view v;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try{
v = (view) View.inflate(Test2.this, R.layout.main2, null);
}catch(Exception e){
System.out.println(" ERR " + e.getMessage()+e.toString());
}
}
}
class view extends View{
public view(Context context) {
super(context);
}
}
Ok tried this, and realized that it doesn't work. The problem is, that the View class does not have methods for adding child views. Child views should only be added to ViewGroups. Layouts, such as LinearLayout, extend ViewGroup. So instead of extending View, you need to extend for example LinearLayout.
Then, in your XML, reference to the layout with:
<my.package.MyView
android:id="#+id/CompId"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
Then in your custom class, inflate and add:
public class MyView extends LinearLayout {
public MyView(Context context) {
super(context);
this.initComponent(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
this.initComponent(context);
}
private void initComponent(Context context) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.foobar, null, false);
this.addView(v);
}
}
Suggestion: avoid naming your classes names very close to already existing classes (eg. View, Activity);
Since you are extending View (which by default does not draw anything specific) you aren't able to see anything in your activity.
Start by extending TextView object to get a feel.
public class MyTextView extends TextView {
public MyTextView(Context c){
super(c);
}
// ----
public class MyActivity extends Activity {
MyTextView myTextView;
#Override
protected void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
setContentView(myTextView = new MyTextView(this);
myTextView.setText("It works!");
}
Hope this helps!