I am playing a bit around with java and kotlin at the moment.
I wanted to have a custom view class which shall be part of my main activity. Therefore I let my class "MyGridView" inherit from View and added some methods.
I then created an MyGridView object (myGrid) in my MainActivity and call the "setPlayTable(playTable)" method, which sets the playTable variable of the object myGrid to playTable. When I later want to use this variable I get a null pointer reference. When debugging I can clearly see, how myGrid's playTable variable is set. But when later called, I get the NullPointerException. Here are the important parts of my code:
Class MyGridView
public class MyGridView extends View {
private HashMap<Integer, Integer> playTable;
public MyGridView(Context context) {
this(context, null);
}
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
blackPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
public void setPlayTable(HashMap<Integer, Integer> playTable){
this.playTable = playTable;
}
public void drawPlayTable(Canvas canvas){
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(42);
this.setNumColumns(10);
this.setNumRows(10);
for(int x = 0; x < 10; x++){
for(int y = 0; y < 10; y++){
int posX = (int)((x+0.5)*cellWidth);
int posY = (int)((x+1)*cellHeight);
Log.d("playtable",this.playTable.toString());
canvas.drawText(Integer.toString(this.playTable.get(10*x+y)), posX, posY, paint);
}
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawPlayTable(canvas);
}
MainActivity (kotlin)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rollDice()
val indexes = (1..100).toList()
var numbers = indexes.shuffled()
playTable = HashMap<Int,Int>(indexes.zip(numbers).toMap())
var myGrid = MyGridView(this)
myGrid.setNumColumns(10)
myGrid.setNumRows(10)
myGrid.setPlayTable(playTable)
myGrid.invalidate()
when I call the "invalidate" method, the onDraw() method is called, which calls the drawPlayTable() method. in there I get the Exception as soon as I try to access the playTable variable.
Why does this happen? Did I by accident set the class instead of the object variable? Please help me to solve this issue :D
Related
Is there a way to color text in TextView or something else in Android during certain time period. So it would start off with fully white text and then the coloring would move from left to right and fill it up during a certain duration.
So for example if the duration would be 10 then the whole line should be color in 10 seconds, but it should also move with the same pace.
Which would look something like this:
There is a way to do it on IOS with CATextLayer, but I haven't yet found a way to do it on Android.
I'm just creating a self-defined TextView in last year,here is my class
public class AKChangeColorTextView extends TextView {
public AKChangeColorTextView(Context context) {
this(context,null);
}
String TAG = "AKChangeColorTextView";
public AKChangeColorTextView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
RectF mRectF;
float mX;
float mY;
public AKChangeColorTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLUE);
PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
mPaint.setXfermode(mode);
float x = 60;
float y = 10;
mY = 0;
mRectF = new RectF(x, y, x + 50, y + 50);
mTPaint = getPaint();
mX = 0;
}
Paint mPaint;
TextPaint mTPaint;
Bitmap shadowBitmap ;
Rect bounds = new Rect();
Canvas textCanvas;
#Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
if (shadowBitmap == null) {
shadowBitmap = Bitmap.createBitmap(getMeasuredWidth(),getMeasuredHeight(), Bitmap.Config.ARGB_8888);
}
if (textCanvas == null) {
textCanvas = new Canvas(shadowBitmap);
}
textCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
if (mTPaint == null) {
mTPaint = getPaint();
}
String content = getText().toString();
mTPaint.getTextBounds(content,0,content.length(),bounds);
textCanvas.drawText(content,0,bounds.height(),mTPaint);
mRectF.set(colorLeft,mY,colorRight,mY+bounds.height()+10);
textCanvas.drawRect(mRectF,mPaint);
canvas.drawBitmap(shadowBitmap,0,0,null);
}
float colorLeft;
float colorRight;
public void setXOffset(float left,float right){
colorLeft = left;
colorRight = right;
invalidate();
}
}
my demo code:
class MainActivity : AppCompatActivity() {
val TAG = "MainActivity"
lateinit var countDownTimer:CountDownTimer
var currentOffsetx = 0
var textWidth = 0
var isIncrease = true
lateinit var txt:AKChangeColorTextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
(findViewById<View>(R.id.tv_hello) as AKChangeColorTextView).apply{
txt = this
}
countDownTimer = object:CountDownTimer(300000,200){
override fun onFinish() {
}
override fun onTick(millisUntilFinished: Long) {
if (textWidth == 0) {
textWidth = txt.width
}
if (currentOffsetx <= textWidth) {
if (isIncrease) {
currentOffsetx += 10
currentOffsetx = min(currentOffsetx, textWidth)
} else {
currentOffsetx -= 10
currentOffsetx = max(currentOffsetx, 0)
}
}
if (currentOffsetx == textWidth) {
isIncrease = false
}else if (currentOffsetx == 0) {
isIncrease = true
}
txt.setXOffset(0f,currentOffsetx.toFloat())
Log.w(TAG,"check current tick:$millisUntilFinished,offsetx:$currentOffsetx,txtWidth:$textWidth")
}
}
countDownTimer.start()
}
}
my xml layout :
<com.example.administrator.myapplication.AKChangeColorTextView
android:id="#+id/tv_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I Found a Love For Aolphn"
android:textColor="#000000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
following is effect
There is a way to do this optimized, simple, smooth and beautiful: Vector Animated Drawables (API21+).
There are a lot of tutorials out there (for example this video) that show how you can make beautiful animations. Basically the steps are following:
create two SVG vector images of your text, one with normal color, the other one with
colored letters. You can do this easily in Adobe Illustrator for example.
Import both into shapeshifter.design.
Create an animation for the second (colored layer) by your liking.
Copy the resulting xml file into your drawables and you're done!
Good luck!
You can use a text spannable and Foreground Color Span and animate one character at a time
I need some help adjusting a function to be constantly updating (<- that may not make sense at first but hopefully a little more explanation will make it clear). This is going to be a long post but please bear with me.
I've got an Activity and a Custom Class. The Activity's Java file only contains a reference to the seekbar that's in it and the OnSeekBarChangeListener. The XML contains said seekbar, and a reference? to the Custom Class (not sure if it's actually called a reference). Here's the code for both:
Java:
public class Painting extends Activity
{
static SeekBar curveBar;
SampleView sampleView;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_painting);
curveBar = (SeekBar)findViewById(R.id.curveBar);
sampleView = new SampleView(this);
curveBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (progress >= 50
{
sampleView.updatePath(progress);
}
else if (progress < 50)
{
sampleView.updatePath((-1) * progress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
Toast.makeText(Painting.this, "Value: " + curveBar.getProgress(), Toast.LENGTH_SHORT).show();
}
});
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
tools:context="com.example.android.postvu.SampleView">
<com.example.android.postvu.SampleView
android:id="#+id/view"
android:layout_height="300dp"
android:layout_width="match_parent"/>
<SeekBar
android:id="#+id/curveBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/view"
android:layout_alignParentBottom="true"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:elevation="50dp"/>
</RelativeLayout>
My Custom Class is what actually draws the canvas with the curve on the top half. In this class I've got 2 constructors:
public SampleView(Context context, AttributeSet attrs)
{
super(context, attrs);
setFocusable(true);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(90);
mPaint.setTypeface(Typeface.SERIF);
mPath = new Path();
makePath(mPath);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.rgb(255,0,0));
mPathPaint.setStyle(Paint.Style.STROKE);
}
public SampleView(Context context)
{
super(context);
setFocusable(true);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(90);
mPaint.setTypeface(Typeface.SERIF);
Log.d("LOGCAT", "" + value);
mPath = new Path();
makePath(mPath);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.rgb(255,0,0));
mPathPaint.setStyle(Paint.Style.STROKE);
}
AND FINALLY the 2 functions that I'm stuck on. The first is simply being called from the seekbar in the Activity and it's just so that I can get the value of the seekbar at all times while it's being moved.
public void updatePath(int seekbarProgress)
{
value = seekbarProgress * 6;
}
The second function is what draws the curve itself based on a Bezier Curve:
public void makePath(Path p)
{
// p.moveTo(250, -300);
p.moveTo(0,0);
// p.cubicTo(-250, -550, 750, -550, 250, -300);
p.cubicTo(0,-400,600,-400,600,0); //semi-circle?
// p.cubicTo(-600, -400, 600, -400, 0, 0); //as far as the curve probably should allow
// p.cubicTo(0, 0, 0, 0, 620,0); //flat line
}
MY ACTUAL QUESTION
How can I change the makePath function to take the value variable from the updatePath function so that I can make the p.cubicTo look like p.cubicTo(0,-400,600,-400,value,0) considering that I'm calling makePath in both of the constructors?
****EDIT****
The 2 constructors from my Custom Class (and relevant function) now look like this:
public SampleView(Context context, AttributeSet attrs)
{
super(context, attrs);
setFocusable(true);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(90);
mPaint.setTypeface(Typeface.SERIF);
mPath = new Path();
// updatePath(value);
makePath(mPath, value);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.rgb(255,0,0));
mPathPaint.setStyle(Paint.Style.STROKE);
}
public SampleView(Context context)
{
super(context);
setFocusable(true);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(90);
mPaint.setTypeface(Typeface.SERIF);
mPath = new Path();
// updatePath(value);
makePath(mPath, value);
Log.d("LOGTAG2", "" + value);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.rgb(255,0,0));
mPathPaint.setStyle(Paint.Style.STROKE);
}
public int updatePath(int seekbarProgress)
{
return value = seekbarProgress * 6;
}
public void makePath(Path p, int number)
{
p.moveTo(0,0);
p.cubicTo(0, 0, 0, 0, number,0); //flat line
}
Android Studio is highlighting updatePath and when I hover over it, it tells me Return value of the method is never used. Unless I'm doing something wrong, I am using that value in both constructors where it says makePath(mPath, value);. I'm not sure what else to do at this point because it doesn't make any sense to me. I really want to know 1) how to fix it and 2) what's causing it (why it's telling me that I am not using it (which I think I am)).
I would like to learn how to exchange data between classes(in Android Studio).
For that purpose I have created three Java classes:
1) GraficActivity.java:
public class GraficActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView iv = (ImageView) findViewById(R.id.testview);
//not working: iv.update(100,100);
DataHolder.setData(100, 100);
}
}
2) DrawingView.java:
public class DrawingView extends ImageView {
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
private int X=200;
private int Y=200;
//not working: X = DataHolder.getX();
//not working: Y = DataHolder.getY();
public void update(int dataX, int dataY) {
X=dataX;
Y=dataY;
this.invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint pinsel = new Paint();
pinsel.setColor(Color.rgb(64, 64, 255));
pinsel.setStrokeWidth(5);
canvas.drawLine(0, 0, X, Y, pinsel);
}
}
3) DataHolder.java:
public class DataHolder {
private static int X;
private static int Y;
public static int getX() {return X;}
public static int getY() {return Y;}
public static void setData(int dataX, int dataY) {X = dataX; Y=dataY;}
}
I included DrawingView in the layout (together with other elements) with the following code in main.xml:
<de.carpelibrum.grafik.DrawingView
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#ffffff"
android:id="#+id/testview" />
The app works in principle, but I could not find a way to transfer data from GraficActivity to DrawingView.
I tried two methods(as indicated in the code above):
Via a separate DataHolder as global variable
With the function update(int, int) in DrawingView.
Finally, I will need to transfer not only two integers, but the content of an array: int data[][];.
How to solve the problem?
Thank you in advance for your suggestions.
Cheers,
Kyriakos.
ImageView does not have a method update(int, int). You should cast the View associated with the id R.id.testView to your type DrawingView. Then update(int, int) should become available at compile-time:
DrawingView iv = (DrawingView) findViewById(R.id.testview);
Also, consider that your DataHolder and DrawingView are both storing position data. Pick one. If the data is specific to an instance of DrawingView, then you don't need DataHolder.
perfect! Thank you.
Regarding the database, I put it in "GraficActivity", sratched "DataHolder", and used a pointer as parameter in the "update" function:
in "GraficActivity":
private int data[][]=new int[10][10];
data[0][0] = 200;
data[0][1] = 100;
iv.update(data);
in "DrawingView":
public void update(int[][] dataXY) {
X=dataXY[0][0];
Y=dataXY[0][1];
this.invalidate();
}
Now this is a good working basis.
Cheers,
Kyriakos.
I have a custom Seek bar that that i made following a tutorial on the net. Here is the code for the CustomSeekBar class.
public class CustomSeekBar extends SeekBar {
private ArrayList<ProgressItem> mProgressItemsList;
public CustomSeekBar(Context context) {
super(context);
}
public CustomSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void initData(ArrayList<ProgressItem> progressItemsList) {
this.mProgressItemsList = progressItemsList;
}
#Override
protected synchronized void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
protected void onDraw(Canvas canvas) {
if (mProgressItemsList.size() > 0) {
int progressBarWidth = getWidth();
int progressBarHeight = getHeight();
int thumboffset = getThumbOffset();
int lastProgressX = 0;
int progressItemWidth, progressItemRight;
for (int i = 0; i < mProgressItemsList.size(); i++) {
ProgressItem progressItem = mProgressItemsList.get(i);
Paint progressPaint = new Paint();
progressPaint.setColor(getResources().getColor(
progressItem.color));
progressItemWidth = (int) (progressItem.progressItemPercentage
* progressBarWidth / 100);
progressItemRight = lastProgressX + progressItemWidth;
// for last item give right to progress item to the width
if (i == mProgressItemsList.size() - 1
&& progressItemRight != progressBarWidth) {
progressItemRight = progressBarWidth;
}
Rect progressRect = new Rect();
progressRect.set(lastProgressX, thumboffset / 2,
progressItemRight, progressBarHeight - thumboffset / 2);
canvas.drawRect(progressRect, progressPaint);
lastProgressX = progressItemRight;
}
super.onDraw(canvas);
}
}
}
I have used this custom widget in a fragment. This fragment has multiple instance of this custom widget.
The fragment is used in multiple activities. There is an activity where the fragment works fine but in another activity where i try to use two of the above fragments i get a NullPointer Exception.
From the stacktrace i can trace the null pointer exception back to the line
if (mProgressItemsList.size() > 0) {
The strange thing is that when i add the fragment to only one framelayout the code works fine. But when i add the fragment to another framelayout in the same activity i get this null pointer exception. I am confused on what is causing this and am wondering what is the best way to tackle this?
The problem was that i was working with the view in the views of my fragment onActivityCreated() method. If you are planning to use the same fragment twice in any activity this is a very bad idea. I had two fragments initialized but only a single fragment and its views was initialized because i was using getActivity().findViewById() .
The solution to this is to work with your fragment's view on onViewCreated(View view, #Nullable Bundle savedInstanceState) and instead of using getActivity().findViewById() using view.findViewById().
I have a simple Java class which extends View in another package, and I am making a custom view using this class. I want to use it as a View in XML from another class, which is an Activity.
My custom View needs some data from that class, so I created an object of Pt class, which extends Activity. The object is created, but when I am use that object for accessing the members of the class that extends Activity, it does not show any members. Am I doing something wrong, or there is a better way to do it?
Here is my code. I have shown what I am expecting within the comments.
public class PlotView extends View {//class to make a custom view
Plot_View obj_plot = new Plot_View();
obj_plot.// here i am expecting it to show the members of that Plot_View class which is extending Activity
class Pt{
float x, y;
Pt(float _x, float _y){
x = _x;
y = _y;
}
}
Pt[] myPath = { new Pt(100, 100), new Pt(200, 200), new Pt(200, 500),
new Pt(400, 500), new Pt(400, 200) };
public PlotView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public PlotView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(3);
paint.setStyle(Paint.Style.STROKE);
Path path = new Path();
path.moveTo(myPath[0].x, myPath[0].y);
for (int i = 1; i < myPath.length; i++){
path.lineTo(myPath[i].x, myPath[i].y);
}
canvas.drawPath(path, paint);
}
}//
and here is my Plot_View Activity .i want to access these Arraylists defined here in this activity
public class Plot_View extends Activity implements OnClickListener {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.plotview);
calculationForPlot();
findViewById(R.id.btn_measure).setOnClickListener(this);
initMirrorMatrix();
drawMatrix();
}
private void calculationForPlot(){
ArrayList<String> al_edit_A_ft = new ArrayList<String>();
ArrayList<String> al_edit_A_inch=new ArrayList<String>();
ArrayList<String>al_edit_B_ft=new ArrayList<String>();
ArrayList<String>al_edit_B_inch= new ArrayList<String>();
float x=0;
AndroidOpenDbHelper androidOpenDbHelperObj = new AndroidOpenDbHelper(this);
SQLiteDatabase sqliteDatabase = androidOpenDbHelperObj.getReadableDatabase();
String q="SELECT * FROM ab_measurement WHERE job_id=" +"\""+Settings.jobid +"\"";
Cursor cursor = sqliteDatabase.rawQuery(q,null);
if (cursor.moveToNext()) {
System.out.println(cursor.getCount());
m=Integer.parseInt(cursor.getString(4));
do {
try{
float a = 0,b = 0;
a=(float) Double.parseDouble(cursor.getString(6));
String number =String.valueOf(a);
System.out.println("aaa ggg"+number);
String int_part =number.substring(0,number.indexOf("."));
String float_part=number.substring(number.lastIndexOf(".")+1,number.length());
System.out.println("aaa values"+int_part);
System.out.println("aaa values"+float_part);
al_edit_A_ft.add(int_part);
al_edit_A_inch.add(float_part);
b= (float) Double.parseDouble(cursor.getString(7));
String number_b =String.valueOf(b);
System.out.println("aaa ggg"+number_b);
String int_part_b =number_b.substring(0,number_b.indexOf("."));
String float_part_b=number_b.substring(number_b.lastIndexOf(".")+1,number_b.length());
System.out.println("aaa values"+int_part_b);
System.out.println("aaa values"+float_part_b);
al_edit_B_ft.add(int_part_b);
al_edit_B_inch.add(float_part_b);
x= (float) Double.parseDouble(cursor.getString(3));
String ft_base =String.valueOf(x);
System.out.println("aaa ggg"+ft_base);
String int_part_ft =ft_base.substring(0,ft_base.indexOf("."));
String float_part_inch=ft_base.substring(ft_base.lastIndexOf(".")+1,ft_base.length());
System.out.println("aaa values"+int_part_ft);
System.out.println("aaa values"+float_part_inch);
}
catch (Exception e) {
}
} while (cursor.moveToNext());
Try this....
Create an object reference variable of Your_Activity type in the Java class, and initialize it in the contructor with the Context passed to it.
Activity class:
public class MyActivity extends Activity {
TextView myView ;
protected void onCreate(android.os.Bundle savedInstanceState) {
myView = (TextView)findViewById(R.id.myView);
Points myPoints = new Points(this);
myPoints.displayMsg("MY NAME IS VIVEK");
}
}
Java class:
private class Points {
public MyActivity mcontext;
////---------- a constructor with the Context of your activity
public Points(MyActivity context){
mcontext = context;
}
public void displayMsg( final String msg){
context.runOnUiThread(new Runnable() {
#Override
public void run() {
mcontext.myView.setText(msg);
}
});
}
}
From the way your commented line of code is incomplete, I assume you are using an auto-complete feature of your IDE.
My first suggestion is to change the name Plot_View to PlotActivity. This will help you avoid confusion when you return to this project in the future. Also, it will help avoid confusion when you ask questions here.
As for your actualy question, I assume you are referring to the following ArrayLists:
ArrayList<String> al_edit_A_ft = new ArrayList<String>();
ArrayList<String> al_edit_A_inch=new ArrayList<String>();
ArrayList<String>al_edit_B_ft=new ArrayList<String>();
ArrayList<String>al_edit_B_inch= new ArrayList<String>();
First you need to realize that these are not members of the Plot_View class. They are declared locally in the calculationForPlot() method. Although, it appears that you have not posted the entire Plot_View class, so you may have declared other ArrayLists elsewhere. If you are indeed referring to the ArrayLists that I pasted above, you will need to declare them as member variables in Plot_View rather than as local variables in calculationForPlot(). Then you can create getter methods to allow your View class to access them.