I'm a starter in Android Programming, and I'm developing a program by modifying some classes I found here. So far I have the DrawView class as follows:
public class DrawView extends View {
private Ball ball1;
private Button kapabut;
public DrawView(Context context) {
super(context);
setFocusable(true);
ball1 = new Ball(context,R.drawable.ortatop);
kapabut=new Button(context); //here, I cannot seem to add a button.
kapabut.setVisibility(VISIBLE);
kapabut.setText("xXx");
}
#Override protected void onDraw(Canvas canvas) {
// move the balls at every canvas draw
ball1.moveBall();
//draw the balls on the canvas
canvas.drawBitmap(ball1.getBitmap(), ball1.x, ball1.y, null);
// refresh the canvas
invalidate();
}
}
The ball is created and moves, but I cannot seem to get the button "kapabut" anywhere. How can I make this button appear, and add an onClick method too?
Any help would be appreciated, thanks.
P.S.: I tried and added a Button using an XML layout, but now I want to make it with this class, and setting setContentView(new DrawView(this)); in Main.java
You can not add other View objects in View's onDraw() method, their is no any addView() method in View class.
To get it work extend your DrawView class with ViewGroup now you can add other View in this. As addView() method belongs to ViewGroup Class.
Something like,
public class DrawView extends ViewGroup {
Related
I call a view class from my activity. Then the view class calls the same activity. Here is the problem, once the activity comes back up, it won't register any more button pushes.(I'm trying to call another view class. Here is some code:
View Class
public class AnimationView extends View {
Activity myActivity;
//...
public AnimationView(Context context, Activity activity) {
super(context);
//...
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//...
myActivity.setContentView(R.layout.activity_home);
}
}
Home Activity
public class HomeActivity extends AppCompatActivity {
private AnimationView mDrawViewA;
///...
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mDrawViewA = new AnimationView(this,this);
start = (Button) findViewById(R.id.startButton);
//...
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//...
setContentView(mDrawViewA);
//calls more views
//......
});
}
I realize now maybe I should have been calling the view classes in different activities, but I would very much like a get all the view classes working within the same activity.
The problem is you're calling setContentView every time you press the "start" button. This method will overwrite the current layout (if any) with the new value you're setting.
What you can do to get the result you're expecting, which, from what I understand, is to add a new AnimationView to your current layout on every button click, you can try something like this:
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
AnimationView animationView = new AnimationView(getApplicationContext());
// I'm using ConstraintLayout as an example, since I don't know exactly what layout you're using
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
// Set the layout params the way you want
addContentView(animationView, params); // This is where the magic happens
}
});
In short, addContentView is the method you should use when you want to add new views into your activity's root layout.
PS.: It's a terribly bad practice to let the views "know" the activity controlling it. It's always the opposite way around: the activity/fragment knows the view(s) it's controlling.
I need a reference to VerticalViewPager in PageFragSanningellerKonsekvens.
I got two ViewPagers: one for horizontal swiping that goes on for ever, and one for vertical swiping that loads three fragments (mid, swipe up, swipe down) that loads content. The horizontal ViewPager loads a new instance of VerticalViewPager on every swipe. I need a reference in the actual fragment that is loaded by the VerticalViewPager, so that I can swipe vertically by tapping a button. I also need a reference to the horizontal ViewPager to allow the first page to have a button that triggers a horizontal swipe.
I've solved it by sending the reference as an argument like this:
FragSanningEllerKonsekvens - The class that initializes the VerticalViewPager.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_sanning_eller_konsekvens, container, false);
initComponents();
setComponents();
return view;
}
private void initComponents() {
verticalViewPager = (VerticalViewPager) view.findViewById(R.id.verticalviewpager);
mStatementPagerAdapter = new TruthDarePagerAdapter(getChildFragmentManager()).newInstance(getChildFragmentManager(),mViewPager, verticalViewPager);
}
Its transfers in TruthOrDarePagerAdapter:
private ViewPager mViewPager;
private VerticalViewPager mVerticalViewPager;
public static TruthDarePagerAdapter newInstance(FragmentManager fm, ViewPager mViewPager, VerticalViewPager mVerticalViewPager){
TruthDarePagerAdapter horizontalPagerAdapter = new TruthDarePagerAdapter(fm);
horizontalPagerAdapter.setViewPager(mViewPager);
horizontalPagerAdapter.setVerticalViewPager(mVerticalViewPager);
return horizontalPagerAdapter;
}
public VerticalViewPager getVerticalViewPager() {
return mVerticalViewPager;
}
public void setVerticalViewPager(VerticalViewPager mVerticalViewPager) {
this.mVerticalViewPager = mVerticalViewPager;
}
private void setViewPager(ViewPager mvViewPager){
this.mViewPager = mvViewPager;
}
private ViewPager getViewPager(){
return mViewPager;
}
#Override
public Fragment getItem(int position) {
PageFragSanningellerKonsekvens frag = new PageFragSanningellerKonsekvens().newInstance(getViewPager(), getVerticalViewPager());
.
.
.
return frag;
}
PageFragSanningellerKonsekvens - The class that needs the reference.
public static PageFragSanningellerKonsekvens newInstance(ViewPager mViewPager, VerticalViewPager mVerticalViewPager){
PageFragSanningellerKonsekvens frag = new PageFragSanningellerKonsekvens();
frag.setViewPager(mViewPager);
frag.setVerticalViewPager(mVerticalViewPager);
return frag;
}
private void setupMenu() {
viewTop = view.findViewById(R.id.sek_top);
viewBottom = view.findViewById(R.id.sek_bottom);
viewTop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getVerticalViewPager().setCurrentItem(0, true);
}
});
viewBottom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getVerticalViewPager().setCurrentItem(2, true);
}
});
}
The code above works excellent until I rotate the device. After rotation the getVerticalViewPager() returns null. In other parts of the application I've used this pattern without any problems: on rotation the ViewPager is sent as a parameter and the application reloads without dropping the reference.
So the conclusion I've drawn is that the VerticalViewPager doesn't get reinitialized on rotation, while PageFragSanningellerKonsekvens is.
My question is; how can I solve it? Can I force it to be reinitialized, or can I obtain a reference to it in some other way?
EDIT 1: I'll think its related to getItem() in the FragmentStatePagerAdapter. It will be called to allocate 3 fragments at every given time. I think this might nullify the getVerticalViewPager() method.
EDIT 2: I moved some code to allow the ViewPager and the button to be initialized in the same class, thus making it somewhat null-proof. Thanks for the help!
Ok this might not be a complete answer but I think it would be too long a comment.
I think you are right that the null pointer happens at getItem in the adapter. (a logcat report to confirm this would be nice).
The reason for this (I think) is that the adapter tries to recreate the inner fragments before the inflation of the ViewPager is complete. Normally I create similar adapters in onCreate because it normally do not rely on anything but a fragmentmanager.
Having this in mind, and the fact that you might have a hard time avoiding the null pointer in the current design, I propose a new design.
Am only at my phone right now so is hard to give you the code I have in mind. For now I just sketch the idea:
Move the getter/setter of ViewPagers from the adapter to FragSanningEllerKonsekvens, leaving the creation of TruthOrDarePagerAdapter only depend on fragment manager
Now do the same for PageFragSanningellerKonsekvens making it simply PageFragSanningellerKonsekvens.newInstance() in getItem of the adapter
Finally, you are now missing the reference to the ViewPagers in PageFragSanningellerKonsekvens PageFragSanningellerKonsekvens, but remember you now have the getters of both ViewPagers in the parent FragSanningEllerKonsekvens
So the buttons now become:
((FragSanningEllerKonsekvens)getParentFragment()).getVerticalViewPager().setCurrentItem(0, true);
And
((FragSanningEllerKonsekvens)getParentFragment()).getVerticalViewPager().setCurrentItem(2, true);
I'm trying to make a bull's eye with random color, and instead of circles I will use squares.
But the thing is that when I run the app on the emulator and when he starts the new activity it stops responding.
This is the main activity, the one that starts the DrawActivity.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent coiso = new Intent(this, Draw.class);
startActivity(coiso);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
And this is the Draw activity, the one that I want to start. (It doesn't have the things that I want to do. Because I can't, the problem is ahead)
public class Draw extends View {
public Draw(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
}
}
Can someone help me? Sorry for the english.
You have this
public class Draw extends View
Your class does not extend Activity
Instead you can do as below
Draw draw = new Draw(this);
setContentView(draw);
Or have a layout linear or relative and place it where you like add your Draw view to the layout after initializing.
setContentView(R.layout.activity_main);
LinearLayout ll = (LinearLayout)findViewById(R.id.linearLayout);
// linear layout or relative layout in activity_main.xml.
// place the layout ahere you want along with other views
Draw draw = new Draw(this);
ll.addView(draw);
// add your customview to linearlayout
Edit:
Remove this
Intent coiso = new Intent(this, Draw.class);
startActivity(coiso);
In your activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
// customize linear layout to your needs.
<LinearLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:id="#+id/linearLayout"
android:orientation="vertical" >
</LinearLayout>
// other widgets
</RelativeLayout>
In your onCreate
setContentView(R.layout.activity_main);
LinearLayout ll = (LinearLayout)findViewById(R.id.linearLayout);
Draw draw = new Draw(this);
ll.addView(draw);
startActivity requires an activity. I would suggest going through the docs
http://developer.android.com/reference/android/app/Activity.html#startActivity(android.content.Intent)
Your Draw class needs to extend Activity rather than View. As you want to start a new Activity, the Draw class, this means that this should extend Activity. Also, you need to Override onCreate() within the Draw class.
If your Draw class is a View, then I would suggest that you add the view to the Layout that you are using using the addView()
You need to make sure that you change Draw extends Activity
You cant intent to a new activity with no layout and no OnCreate As far as I know.
try creating a regular activity which extends Activity and implement your Draw there.
public class DrawActivity extends Activity {
#SuppressLint("ShowToast")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
Toast.makeText(DrawActivity.this, "YO", Toast.LENGTH_LONG);
}
and from there implement your draw functions.
or create a JAVA class which implements your draw needs and use it in main screen.
I was wondering how do i attach this(OnGenericMotionListener) listener inside an activity. Do i have to register it to each view? thanks
note: please provide code.
To add any interface to a class in java you just need to add the word implements and then the class name to the top of the activity declaration. So to add the OnGenericMotionListener you would use the code below.
public class MyActivity extends Activity implements OnGenericMotionListener {
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView myView = new TextView(this);
myView.setOnGenericMotionListener(this);
}
#Override
public boolean onGenericMotion(View view, MotionEvent event) {
return false;
}
}
This would set the GenericMotionListener for myView so when the event occurs it will call the onGenericMotion function inside of your activity. If you want to attach it to multiple views just use a switch on the id of the view passed to the onGenericMotion function.
I'm attempting to create a ListView where I can draw some basic shapes into each item in the ListView. I've found many examples using Views/Layouts within a ListView to add an image etc, but am unsure how I would draw into each one using a Canvas or similar. Furthermore these examples seem to all work in slightly different ways, so I was wondering what the best strategy is.
At the moment I just have a Main class which populates the ListView with basic text.
Main.java
public class Main extends Activity {
private ListView listView;
String[] list = {"One","Two","Three"};
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
listView = (ListView)findViewById(R.id.ListView1);
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, list));
}
}
Now I gather I'll need change the Adapter bit here, and also write another class which possibly extends View, which I can draw to, then add this as an item in the ListView?
Thanks for your help in advance.
You would need to subclass your ListView to a custom implementation.
public class CustomListAdapter extends ArrayAdapter<CustomRowData> {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
CustomRowData currentRow = getItem(position);
View customRowView = .... // such as CustomRowView below.
...
...
return customRowView;
}
}
You can change the view for each row in the ListView by replacing the ... with the appropriate View code.
For example, you can use SurfaceView to draw on it.
class CustomRowView extends SurfaceView {
...
...
#Override
public void onDraw(Canvas canvas) {
// Use |canvas| to draw on..
}
}
The above code isn't tested, but hopefully will drive you to the right direction. Make sure you optimize your drawing such as use caching when available, preprocess, etc.