Android Casting Custom View - android

This is my view's XML file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="#+id/bsv_edit_beaconname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:inputType="textPersonName"
android:text="Beacon Name" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="#+id/bsv_check_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/cinit_table_isfixpoint" />
<CheckBox
android:id="#+id/bsv_check_draw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/cinit_table_drawbeacon" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:id="#+id/bsv_btn_setpos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="set_position_click"
android:text="#string/cinit_set_position" />
<TextView
android:id="#+id/bsv_text_pos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Position ?" />
</LinearLayout>
With the corresponding java class being the following
package talogs.beacontalogs;
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
public class BeaconSetupView extends LinearLayout {
private static final String TAG = "BeaconSetupView";
private EditText edit_beaconName;
private CheckBox check_isFixpoint;
private CheckBox check_draw;
private Button btn_setpos;
private TextView text_pos;
public BeaconSetupView(Context context) {
this(context, null);
}
public BeaconSetupView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public BeaconSetupView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public void init(Context context) {
// inflate(getContext(), R.layout.beacon_setup_view, this);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate( R.layout.beacon_setup_view, this );
edit_beaconName = (EditText) findViewById(R.id.bsv_edit_beaconname);
check_isFixpoint = (CheckBox) findViewById(R.id.bsv_check_fix);
check_draw = (CheckBox) findViewById(R.id.bsv_check_draw);
btn_setpos = (Button) findViewById(R.id.bsv_btn_setpos);
text_pos = (TextView) findViewById(R.id.bsv_text_pos);
}
public void setPosition(Point point) {
Log.v(TAG, "setting position to " + point.toString());
text_pos.setText(String.format("(%d, %d)", point.x, point.y));
}
}
My custom view BeaconSetupView is created programmatically using this code when a button in an activity is pressed.
public void btn_addbeacon_Click(View view) {
BeaconSetupView beacon = new BeaconSetupView(this);
beaconList.addView(beacon, beaconList.getChildCount() - 1);
}
The button that's part of the custom view calls this method:
public void set_position_click(View view) {
ViewParent parent1 = view.getParent();
ViewParent parent2 = parent1.getParent();
BeaconSetupView bsv = (BeaconSetupView) view.getParent().getParent();
Log.v(LOG_TAG, "set_position called, point is currently " + String.valueOf(lastClicked));
if (lastClicked != null) {
bsv.setPosition(lastClicked);
}
}
The problem is that the button click cannot be implemented outside of the root activity (because it has data that I need), but I also need to get its corresponding BeaconSetupView. Calling view.getParent().getParent() and casting it results in a ClassCastException. So I tried changing the root element of the XML layout to BeaconSetupView, but that causes the app to crash when the view is first added to the activity.
I either need a way to cast my custom class properly and still be able to add it programmatically to my activity, or I need to be able to access the activity's instance from another class that doesn't have a reference to it. What are my options?

Related

Android custom EditTextPreference UI is not getting updated

I am trying to customise an EditTextPreference to display a textview(i.e to display value of the preference) and a clear/delete button on its right side.
I created CustomEditTextPreference.java
package com.customedittextpreference;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.Image;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
/**
* Created by cyong on 23/04/16.
*/
public class CustomEditTextPreference extends EditTextPreference {
private ImageButton clearButton;
private TextView valueTextView;
public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setupChangeListener();
}
public CustomEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setupChangeListener();
}
public CustomEditTextPreference(Context context) {
super(context);
setupChangeListener();
}
#Override
protected void onBindView(View view) {
super.onBindView(view);
valueTextView = (TextView) view.findViewById(R.id.value_textview);
clearButton = (ImageButton) view.findViewById(R.id.clear_button);
clearButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setText("");
}
});
String valueString = getText();
Log.v(Settings.APP_NAME, "refreshValue(): valueString=" + valueString);
valueTextView.setText(valueString);
toggleClearButton(valueString);
}
private void toggleClearButton(String value)
{
if (value.length()==0)
{
clearButton.setVisibility(View.GONE);
}
else
{
clearButton.setVisibility(View.VISIBLE);
}
}
private void setupChangeListener()
{
setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String newStringValue = (String) newValue;
valueTextView.setText(newStringValue);
toggleClearButton(newStringValue);
return true;
}
});
}
}
CustomEditTextPreference class use the layout below(i.e prefwidget_edittext.xml) as widget layout
<?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="horizontal"
android:descendantFocusability="blocksDescendants"
android:padding="0dp">
<TextView
android:id="#+id/value_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_gravity="center_vertical"
android:singleLine="true" />
<ImageButton
android:id="#+id/clear_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:layout_marginRight="5dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:layout_gravity="center_vertical"
android:src="#mipmap/delete_icon"
android:background="#00000000"
/>
</LinearLayout>
I specify my custom EditTextPreference in a preferences_list.xml under res/xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:key="status_choice"
android:entries="#array/array_status_entries"
android:entryValues="#array/array_status_values"
android:title="#string/choose_status_title"
android:summary="%s"
android:defaultValue="0"
/>
<CheckBoxPreference
android:defaultValue="false"
android:key="has_email"
android:title="#string/has_email_title" >
</CheckBoxPreference>
<com.customedittextpreference.CustomEditTextPreference
android:widgetLayout="#layout/prefwidget_edittext"
android:title="#string/productcode_title"
android:key="code"/>
</PreferenceScreen>
I can click on the edittextpreference and enter a string. The string entered would be saved, but would not display in textview of my custom widget layout after that. However, if I kill my app, and start it again, the textview would display the saved string. Now, when I click on the clear/delete button, I can see the value being deleted in but, the UI is not being updated to clear the string the textview and hide the clear/delete button.
For convenience, I have uploaded my sample project into github below:
Sample GitHub Project
Seems like notifyChanged() needs to be called when updating a Preference.
I noticed calls setTitle() and setSummary() would update the UI. It turns out, notifyChanged() is called in those both those functions.
Update the github project with the fix.
GitHub Project

View Custom Layout in grapical layout edit screen

This is my source of testing Custom Layout (shows image and label).
XML CODE
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/screen_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#3535ff"
android:orientation="vertical"
android:padding="1dp" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#000000"
android:padding="20dp" >
<ImageView
android:id="#+id/screen_image"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:background="#000000"
android:scaleType="centerInside"
android:src="#drawable/cam_1_20130117_105601_118" />
<TextView
android:id="#+id/screen_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/screen_image"
android:layout_centerHorizontal="true"
android:layout_marginBottom="3dp"
android:background="#95000000"
android:gravity="center_vertical|center_horizontal"
android:text="사출성형기 1호기"
android:textColor="#ffffff" />
</RelativeLayout>
</LinearLayout>
JAVA CODE
package com.example.testlayout;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.testscreen.R;
public class CustomScreen extends LinearLayout {
LinearLayout mLayout = null;
TextView mLabel = null;
ImageView mImage = null;
public CustomScreen(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomScreen(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomScreen(Context context) {
super(context);
init();
}
void init() {
LayoutInflater inflater = (LayoutInflater)getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.screen, this, true);
// mLabel = (TextView)findViewById(R.id.screen_label);
// mImage = (ImageView)findViewById(R.id.screen_image);
if (isInEditMode()) {
return;
}
}
}
With this code, I checked on Nexus One. It displays well.
The problem is on editor mode. Exactly on xml editer with preview.
When I add this view, error message appeared.
The following classes could not be instantiated :
- com.example.testlayout.CustomScreen (Open Class, Show Error Log) See the Error Log (Window > Show View) for more details. Tip: Use
View.isInEditMode() in your custom views to skip code when shown in
Eclipse
I want to check it on edit mode.
How can I check well like other views?
you have to add (!isInEditMode()) in each constructor. which tells if it not in edit Mode then initialized the stuff
if(!isInEditMode())
init(context);
and for initializing stuff follow this
also have a look at this

Simple custom control - Force closed

I have created an android project using eclipse.the default system generated code looked as below
package com.rmycustomclass.bengler;
import android.app.Activity;
import android.os.Bundle;
public class RMyCustomClassActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
I wanted to try a simple custom control , so i changed the code as below. when i searched the web to create a simple custom control there are mentioned like "create class by subclassing a View". so tried as below by modifying the code.but it was not running and always force closed.
package com.rmycustomclass.bengler;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class RMyCustomClassActivity extends View {
private Paint myPaint;
public RMyCustomClassActivity(Context cxt, AttributeSet attribute){
super(cxt,attribute);
init();
}
public RMyCustomClassActivity(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
public void init(){
myPaint = new Paint();
myPaint.setTextSize(12);
myPaint.setColor(0xFF668800);
myPaint.setStyle(Paint.Style.FILL);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawText("TEEEST", 100, 100, myPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
this.setMeasuredDimension(150,200);
}
}
Below is my xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent" android:orientation="vertical">
<TextView
android:id="#+id/textView1"
android:text="Enter text"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tableLayout1">
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:layout_weight="1">
</Button>
<Button android:layout_width="wrap_content" android:id="#+id/button1" android:layout_height="40dip" android:text="My button" android:layout_weight="1"></Button>
<test.control
android:id="#+id/control"
android:layout_height="match_parent"> </test.control>
</TableLayout>
</LinearLayout>
When you create a project in eclipse it links your activity (RMyCustomClassActivity in your case) as the launcher in Android manifest...But since you have changed the activity to a View
android runtime cannot find the activity to launch...See your manifest file and you will find your class as the launcher activity
add android:layout_width="match_parent"
<test.control
android:id="#+id/control"
android:layout_height="match_parent"
android:layout_width="match_parent"
>

Creating custom view from xml

I would like to add the same horizontal scrollable row of buttons like so
<HorizontalScrollView [...]>
<LinearLayout [...] android:orientation="horizontal">
<Button android:id="#+id/btn1" [..] />
<Button [..] />
[...]
</LinearLayout>
</HorizontalScrollView>
(toolbar.xml) to the bottom of every activity in my application. Rather than have to specify the click listeners for each button in every single activity, I'd like to be able to do all of that in one place and then just import the control each time. I figure I can do something like
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.example.ButtonBar android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_alignParentBottom="true"
android:layout_below="#+id/pagecontent" />
<LinearLayout android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/pagecontent">
<!-- the rest of each activity's xml -->
</LinearLayout>
to include the button bar on the screen, and then do something like
package com.example;
import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.HorizontalScrollView;
public class ButtonBar extends HorizontalScrollView implements OnClickListener
{
public ButtonBar(Context context, AttributeSet attrs)
{
super(context, attrs);
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.toolbar, null);
Button btn1 = (Button) view.findViewById(R.id.button1);
btn1.setOnClickListener(this);
// and so on for the rest of the buttons
addView(View);
}
#Override
public void onClick(View v)
{
Intent intent = null;
if (v.getId() == R.id.btn1)
{
intent = new Intent(getContext(), FirstScreen.class);
}
else if (v.getId() == R.id.btn2)
{
intent = new Intent(getContext(), SecondScreen.class);
}
// and so on
if (intent != null) getContext().startActivity(intent);
}
}
but then what? How do I actually get it to display? Are there other methods I should be overriding? Is there a better / more appropriate way of doing this?
Take a look at a custom control ProgressView in my app BBC News, and one layout that uses it.
http://svn.jimblackler.net/jimblackler/trunk/workspace/NewsWidget/src/net/jimblackler/newswidget/ProgressView.java
http://svn.jimblackler.net/jimblackler/trunk/workspace/NewsWidget/res/layout/progress_view.xml
http://svn.jimblackler.net/jimblackler/trunk/workspace/NewsWidget/res/layout/main.xml

Drawing on a screen with other views in android

I have been searching for the past few hours to the answer to a very dumb question. I know how to draw on the canvas in android if you extend the view class, modify onDraw and set setContentView() to a new instance of that class. However, I need to also have 2 TextViews and 2 EditTexts at the bottom of the activity and if setContentView() is set to only have that view, these views will, obviously, not display. How can put all of these on the screen?
EDIT: Here is my code: (the package name is android.physicsengine)
package android.physicsengine;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
import android.widget.RelativeLayout;
public class ResultantForceEngine extends Activity {
private EditText mag;
private EditText dir;
private View image;
private RelativeLayout layout;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.resultant_force);
mag = (EditText)findViewById(R.id.magnitude);
dir = (EditText)findViewById(R.id.direction);
}
public class MyView extends View{
public MyView(Context context){
super(context);
}
public MyView(Context context, AttributeSet attrs){
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas){
canvas.drawColor(Color.BLACK);
Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(Color.RED);
canvas.drawLine(canvas.getWidth()/2, canvas.getHeight()/2-200, canvas.getWidth()/2 ,canvas.getHeight()/2+200, circlePaint);
canvas.drawLine(canvas.getWidth()/2-200, canvas.getHeight()/2, canvas.getWidth()/2+200 ,canvas.getHeight()/2, circlePaint);
}
}
}
and the xml
<view class="android.physicsengine.ResultantForceEngine$MyView"
android:id="#+id/image"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView android:id="#+id/magText"
android:text="Magnitude (N) ="
android:textSize="15dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3dip"
android:gravity="center_vertical"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true" />
<EditText android:id="#+id/magnitude"
android:inputType="numberDecimal"
android:layout_alignParentBottom="true"
android:layout_toRightOf ="#id/magText"
android:layout_width="wrap_content"
android:padding="3dip"
android:layout_height="wrap_content" />
<TextView android:id="#+id/dirText"
android:text="Angle (deg) ="
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15dip"
android:layout_alignParentBottom="true"
android:layout_toRightOf ="#id/magnitude"
android:padding="3dip"
android:gravity="center_vertical" />
<EditText android:id="#+id/direction"
android:inputType="numberDecimal"
android:layout_alignParentBottom="true"
android:layout_toRightOf ="#id/dirText"
android:layout_alignParentRight="true"
android:layout_height="wrap_content"
android:padding="3dip"
android:layout_width="wrap_content"/>
Basically you need to define your XML file with your custom view class and the other widgets you have. In your case, there would be the custom view, 2 textviews and 2 edittexts in the XML file.
You define the custom view in XML just like any other widget, except you use the namespace of the view and the class name.
<com.example.android.myCustomView
android:id="#+id/my_custom_view"
...
Then inside your activity a simple call
setContentView(R.layout.main);
Edit: The problem is your class is private, so it "isn't seen" when your activity makes a call the layout and tries to inflate it.
Edit2: Of course this won't work, you're using an inner class! You have to communicate stuff like this if you expect to get answers.
The XML syntax for an inner class is different.
<view class="com.example.android.MyClass$MyInnerClass"
You should be able to use the class that you extended in your res/layout/main.xml just like you would any other View class, and add your TextView and EditTexts in the layout .xml file like normal. I have not personally done this, but I have used custom View classes in this way.
Then for your setContentView you would just use the layout .xml file like:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...

Categories

Resources