In an attempt to write a bit less code every time I wanted a SeekBar and a corresponding TextView showing it's numerical value, I wrote the following abstract class:
abstract public class SeekBarWrapper {
SeekBar bar;
TextView valueText;
int value = 0;
int minValue;
int divisor;
public SeekBarWrapper(SeekBar sb, TextView tv, int value, int minValue,
int divisor){
this.bar = sb;
this.valueText = tv;
this.value = value;
this.minValue = minValue;
this.divisor = divisor;
setListener();
}
private void setListener(){
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) { }
#Override
public void onStartTrackingTouch(SeekBar seekBar) { }
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if(!fromUser) return;
value = progress + minValue;
valueText.setText(Integer.toString(value/divisor));
sendValue();
}
});
}
abstract protected void sendValue();
public void updateValue(int newValue){
if(newValue == value) return;
value = newValue;
valueText.setText(Integer.toString(value));
bar.setProgress(value*divisor-minValue);
}
}
For each concrete SeekBar I'll write a nested class, for example:
class VolumeBarWrapper extends SeekBarWrapper{
public VolumeBarWrapper(SeekBar s, TextView t, int v, int min, int div){
super(s, t, v, min, div);
}
public void sendValue(){
someCallback.volume(this.value);
}
}
And instantiate like so:
VolumeBarWrapper volume;
// later:
volume = new VolumeBarWrapper((SeekBar) view.findViewById(R.id.volume_bar),
(TextView) view.findViewById(R.id.volume_value), 300, 0, 70);
It's functional, and seemingly an improvement. What I would like to know:
Is there is some way to make this an anonymous inner class, or another method to further condense the per-instance code?
And less pressingly:
Am I abusing the "wrapper" label, doesn't it have some specialized meaning in pattern-speak?
Is this design "bad" from an OOP perspective (I'm still trying to school myself in this regard)?
You can always make a better SeekBar , and use it everywhere:
public class VersatileSeekBar extends SeekBar implements SeekBar.OnSeekBarChangeListener {
private TextView mTextView;
private ChangeHandler mChangeHandler;
public void bindDisplayToChange(TextView textView,ChangeHandler handler) {
mTextView = textView;
mChangeHandler = handler;
}
public VersatileSeekBar(Context context) {
super(context);
init();
}
public VersatileSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public VersatileSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(mChangeHandler != null && mTextView != null){
mChangeHandler.onChange(i,mTextView);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
private void init(){
this.setOnSeekBarChangeListener(this);
}
public static abstract class ChangeHandler{
public abstract void onChange(int value,TextView textView);
}
}
Code to call :
myVersatileSeekBar.bindDisplayToChange(myTextView, new VersatileSeekBar.ChangeHandler() {
#Override
public void onChange(int value, TextView textView) {
textView.setText("level :" + value * 100);
}
});
Related
I have recyclerView where i have added a editText. But when I type text to one edittext, text shows another edittext too. Here is the image..
Above image, I type 100 to other item, but it also shows in Settlements
Here is my adapter:
public class AdapterSectionRecycler extends SectionRecyclerViewAdapter<SectionHeader, Child, SectionViewHolder, ChildViewHolder> {
Context context;
private final OnItemClickListener listener;
public interface OnItemClickListener {
void onItemClick(Child child,Boolean isChecked);
}
public AdapterSectionRecycler(Context context, List<SectionHeader> sectionItemList,OnItemClickListener listener) {
super(context, sectionItemList);
this.context = context;
this.listener = listener;
}
#Override
public SectionViewHolder onCreateSectionViewHolder(ViewGroup sectionViewGroup, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.section_item, sectionViewGroup, false);
return new SectionViewHolder(view);
}
#Override
public ChildViewHolder onCreateChildViewHolder(ViewGroup childViewGroup, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_layout, childViewGroup, false);
return new ChildViewHolder(view);
}
#Override
public void onBindSectionViewHolder(SectionViewHolder sectionViewHolder, int i, SectionHeader sectionHeader) {
Log.e("name section--",sectionHeader.getSectionText());
sectionViewHolder.name.setText(sectionHeader.getSectionText());
}
#Override
public void onBindChildViewHolder(ChildViewHolder childViewHolder, int i, int i1, Child child) {
childViewHolder.chk_answer.setText(child.getAnswerName());
childViewHolder.tv_surveyAnswerId.setText(String.valueOf(child.getAnswerId()));
childViewHolder.chk_answer.setChecked(false);
childViewHolder.etPercentage.setImeOptions(EditorInfo.IME_ACTION_DONE);
childViewHolder.etsl.setVisibility(View.GONE);
childViewHolder.chk_answer.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
listener.onItemClick(child,true);
}else{
listener.onItemClick(child,false);
}
}
});
childViewHolder.etPercentage.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
}
Here is my Child View holder
public class ChildViewHolder extends RecyclerView.ViewHolder {
CheckBox chk_answer;
EditText etPercentage;
EditText etsl;
TextView tv_surveyAnswerId;
public ChildViewHolder(View itemView) {
super(itemView);
chk_answer = (CheckBox) itemView.findViewById(R.id.chk_answer);
etPercentage = (EditText) itemView.findViewById(R.id.etPercentage);
etsl = (EditText) itemView.findViewById(R.id.etsl);
tv_surveyAnswerId = (TextView) itemView.findViewById(R.id.tv_surveyAnswerId);
}
}
I call from activity:
AdapterSectionRecycler adapterSectionRecycler = new AdapterSectionRecycler(this, sections, new AdapterSectionRecycler.OnItemClickListener() {
#Override
public void onItemClick(Child child, Boolean isChecked) {
}
});
recyclerView_land_conversion.setAdapter(adapterSectionRecycler);
What is the wrong with my code? Please help me..
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
adPageSelectListener.onPageChanged(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
You can create your own NonSwipableViewPager like this:
public class NonSwipeableViewPager extends ViewPager {
public NonSwipeableViewPager(Context context) {
this(context, null);
}
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
just override OnTouchEvent and onInterceptTouchEvent method and return false.
I have a ListView that can have new rows appended onto the bottom by calling notifyDataSetChanged(); and increasing the line count by 1. The ListView contains rows of EditTexts.
After calling notifyDataSetChanged(); I want to keep the values that have previously been entered by the user. It seems to be working as long as I don't go back and update one of the values I have already entered after calling notifyDataSetChanged();. Code is below:
public class AddPeopleNewProcedureActivity extends AppCompatActivity {
private ListView addPeopleListView;
private CustomAdapterClass customAdapter;
private FloatingActionButton fab;
private int lineCount;
private EditText personsNameET;
private EditText personsPhoneET;
private List<String> personsName;
private List<String> personsPhone;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addpeoplenew_activity);
setupActivityReferences();
inflateListView();
setupClickListeners();
}
private void setupClickListeners() {
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
lineCount = lineCount +1;
customAdapter.notifyDataSetChanged();
}
});
}
private void inflateListView() {
customAdapter = new CustomAdapterClass();
addPeopleListView.setAdapter(customAdapter);
}
private void setupActivityReferences() {
addPeopleListView = (ListView) findViewById(R.id.listViewAddPeople);
fab = findViewById(R.id.fabAddPerson);
lineCount = 1;
personsName = new ArrayList<String>();
personsPhone = new ArrayList<String>();
}
public class CustomAdapterClass extends BaseAdapter {
#Override
public int getCount() {
return lineCount;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null){
view = getLayoutInflater().inflate(R.layout.row_addpersonnew,null);
}
personsNameET = (EditText) view.findViewById(R.id.personNameEditText);
personsPhoneET = (EditText) view.findViewById(R.id.personPhoneNoEditText);
final int rowClicked = i;
if (personsName != null && !personsName.isEmpty() && !(rowClicked >= personsName.size())){
personsNameET.setText(personsName.get(rowClicked));
}
if (personsPhone != null && !personsPhone.isEmpty() && !(rowClicked >= personsPhone.size())){
personsPhoneET.setText(personsPhone.get(rowClicked));
}
personsNameET.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if(!personsName.isEmpty()){
if (!(rowClicked >= personsName.size())){
personsName.set(rowClicked,personsNameET.getText().toString());
System.out.println("Set "+rowClicked + "Value is: " + personsName.get(rowClicked));
}else{
personsName.add(rowClicked,personsNameET.getText().toString());
System.out.println("Added" +rowClicked + "Value is: " + personsName.get(rowClicked));
}
} else{
personsName.add(rowClicked,personsNameET.getText().toString());
System.out.println("Added" +rowClicked + "Value is: " + personsName.get(rowClicked));
}
}
});
personsPhoneET.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
}
});
return view;
}
}
}
You are using twice this code snippet in your code. Please remove blank one :
personsPhoneET.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
}
});
Do like this :
public class AddPeopleNewProcedureActivity extends AppCompatActivity {
private ListView addPeopleListView;
private CustomAdapterClass customAdapter;
private FloatingActionButton fab;
private int lineCount;
private EditText personsNameET;
private EditText personsPhoneET;
private List<String> personsName;
private List<String> personsPhone;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addpeoplenew_activity);
setupActivityReferences();
inflateListView();
setupClickListeners();
}
private void setupClickListeners() {
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
lineCount = lineCount +1;
customAdapter.notifyDataSetChanged();
}
});
}
private void inflateListView() {
customAdapter = new CustomAdapterClass();
addPeopleListView.setAdapter(customAdapter);
}
private void setupActivityReferences() {
addPeopleListView = (ListView) findViewById(R.id.listViewAddPeople);
fab = findViewById(R.id.fabAddPerson);
lineCount = 1;
personsName = new ArrayList<String>();
personsPhone = new ArrayList<String>();
}
public class CustomAdapterClass extends BaseAdapter {
#Override
public int getCount() {
return lineCount;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null){
view = getLayoutInflater().inflate(R.layout.row_addpersonnew,null);
}
personsNameET = (EditText) view.findViewById(R.id.personNameEditText);
personsPhoneET = (EditText) view.findViewById(R.id.personPhoneNoEditText);
final int rowClicked = i;
if (personsName != null && !personsName.isEmpty() && !(rowClicked >= personsName.size())){
personsNameET.setText(personsName.get(rowClicked));
}
if (personsPhone != null && !personsPhone.isEmpty() && !(rowClicked >= personsPhone.size())){
personsPhoneET.setText(personsPhone.get(rowClicked));
}
personsNameET.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
if(!personsName.isEmpty()){
if (!(rowClicked >= personsName.size())){
personsName.set(rowClicked,personsNameET.getText().toString());
System.out.println("Set "+rowClicked + "Value is: " + personsName.get(rowClicked));
}else{
personsName.add(rowClicked,personsNameET.getText().toString());
System.out.println("Added" +rowClicked + "Value is: " + personsName.get(rowClicked));
}
} else{
personsName.add(rowClicked,personsNameET.getText().toString());
System.out.println("Added" +rowClicked + "Value is: " + personsName.get(rowClicked));
}
}
});
}
I'm new to Android development. I'm facing a dead end developing an app for a project. Please take some time and help me out.
The problem:
I am generating some EditText views nested in a LinearLayout using a for loop.
For example:
LinearLayout rootView = (LinearLayout) findViewById(R.id.rootview);
for (int i=0,j=10;i<j;i++) {
EditText et = new EditText(this);
rootView.addView(et);
et.setHint("EditText No. "+ i);
et.setId(i);
} // This code is for example purposes only.
Now, I can't seem to understand how I can set an addTextChangedListener on the EditText that is focused at a particular time and set that text on other EditTexts. Please tell me what approach should I adopt to achieve this. I tried my best to explain the problem; however, if there is still any ambiguity, feel free to comment and ask. I'm waiting for a solution to this problem.
In terms of screenshots:
What I have:
What I want:
I hope this clears things up!
**
EDIT:
Thanks to TylerSebastian for the solution. I got it to work. Here is the final code: (Inside OnCreate() method)
final LinearLayout rootView = (LinearLayout) findViewById(R.id.rootview);
for (int i=0,j=10;i<j;i++) {
final EditText et = new EditText(this);
rootView.addView(et);
et.setHint("EditText No. "+ i);
et.setId(i);
final TextWatcher textwatcher = new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(final Editable s) {
for (int i=0;i<10;i++){
EditText view = (EditText) findViewById(i);
if (view != et){
view.setText(s.toString());
}
}
}
};
et.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
et.addTextChangedListener(textwatcher);
} else {
et.removeTextChangedListener(textwatcher);
}
}
});
}
**
I don't have access to a machine with AS on it atm so no guarantee that the following is bug-free, but this should point you in the right direction:
final LinearLayout rootLayout = ...;
// within your loop
et.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void afterTextChanged(final Editable s) {
for (int i = 0; i < rootLayout.getChildCount(); i++) {
View view = rootLayout.getChildAt(i);
if (view instanceof EditText && view != et) {
((EditText) view).setText(s.toString());
}
}
}
});
edit: so the above will cause an infinite loop - see my comment below
How about:
final LinearLayout rootLayout = ...;
// again, within your loop
TextWatcher textWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void afterTextChanged(final Editable s) {
for (int i = 0; i < rootLayout.getChildCount(); i++) {
View view = rootLayout.getChildAt(i);
if (view instanceof EditText && view != et) {
((EditText) view).setText(s.toString());
}
}
}
};
et.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
((EditText) view).addTextChangedListener(textWatcher);
} else {
((EditText) view).removeTextChangedListener(textWatcher);
}
}
});
basically, only the focused element will have the textwatcher
first add a LinearLayout in your XML like that
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
then create a new class
public class EditTextCust extends RelativeLayout {
EditText status;
public EditTextCust(Context context, Model post, int inputType,TextWatcher textWatcher) {
super(context);
inflate(context, R.layout.edit_text_cust, this);
status = (EditText) findViewById(R.id.editText);
status.setInputType(inputType);
post.setData(status.getText().toString());
status.setHint(post.getHint());
status.addTextChangedListener(textWatcher);
}
public String getText() {
return status.getText().toString();
}
public EditTextCust(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextCust(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
and creat new XML file names edit_text_cust for this custom view class
<EditText
android:id="#+id/dateEditText"
android:layout_width="match_parent"
android:background="#android:color/transparent"
android:padding="#dimen/_5sdp"
android:layout_height="match_parent"
android:textSize="#dimen/_12sdp" />
and creat model class to set your data
public class Model {
String hint;
String id;
String data;
public String getHint() {
return hint;
}
public void setHint(String hint) {
this.hint = hint;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
and in your class inside the for loop but this code
Model model = new Model();
model.setHint("HINT");
model.setId("1");
editTextCust = new EditTextCust(this, editTextCustModel, InputType.TYPE_CLASS_NUMBER, new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// getText from here use
s.toString();
}
#Override
public void afterTextChanged(Editable s) {
}
});
linearLayout.addView(editTextCust);
it's work with me correctly, and if you didn't understand any thing from this code just add comment and i will help you :)
I'm using flow library(https://github.com/square/flow) to display screens in my app. I have a screen with map view, I implemented it like this:
public class MainView extends LinearLayout implements OnMapReadyCallback {
private MapView mMapView;
private MainScreen mScreen;
public MainView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(VERTICAL);
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mScreen = Flow.getKey(this);
mMapView = (MapView)findViewById(R.id.map);
mMapView.onCreate(mScreen.getGoogleMapState());
mMapView.getMapAsync(this);
mMapView.onResume();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
sInstance = null;
MainScreen screen = Flow.getKey(this);
if(mMapView != null) {
mMapView.onPause();
mMapView.onSaveInstanceState(mScreen.getGoogleMapState());
mMapView.onDestroy();
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
mScreen.setMapReady(true);
}
}
My MainScreen class is saving map state:
public class MainScreen implements Parcelable {
private Bundle googleMapState = new Bundle();
private boolean mMapReady;
public MainScreen(Context context) {
Flow.get(context).setHistory(History.emptyBuilder().push(this).build(), Direction.REPLACE);
}
public Bundle getGoogleMapState() {
return googleMapState;
}
public void setGoogleMapState(Bundle googleMapState) {
this.googleMapState = googleMapState;
}
public void setMapReady(boolean mapReady) {
mMapReady = mapReady;
}
public boolean isMapReady() {
return mMapReady;
}
protected MainScreen(Parcel in) {
googleMapState = in.readBundle();
mMapReady = in.readInt() == 1;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeBundle(googleMapState);
dest.writeInt(mMapReady ? 1 : 0);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<MainScreen> CREATOR = new Parcelable.Creator<MainScreen>() {
#Override
public MainScreen createFromParcel(Parcel in) {
return new MainScreen(in);
}
#Override
public MainScreen[] newArray(int size) {
return new MainScreen[size];
}
};
}
But the google map view is recreated every time app is resumed. What I am doing wrong? I want that google map would be resumed just the way it was before leaving app.