First, I have multiple EditTexts in a Framelayout which wrapped by a ScollView.
I already use below code to let ScrollView scroll up when keyboard is shown -
((Activity) getContext()).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
Also, I tried ADJUST_PAN in above code and nothing changed.
Here is the problem - when I typing in one of those EditTexts, the ScrollView scrolled up automatically which lead to my current editing EditText invisible.
I'm wondering why did this happened? Is my current editing EditText lost focus when typing on the keyboard? And how do I fix it?
By the way I didn't using any xml for the layout. All layouts are written in Java.
The main layout is -
public class PoorEditScroll extends ScrollView {
PoorEdit poorEdit;
public PoorEditScroll(Context context) {
super(context);
initUI();
}
public PoorEditScroll(Context context, AttributeSet attrs) {
super(context, attrs);
initUI();
}
private void initUI(){
setScrollContainer(false);
poorEdit = new PoorEdit(getContext());
this.addView(poorEdit);
}
this.addView(poorEdit);
}
public void toJson(String s) {
poorEdit.toJson(s);
}
public void loadJson(String s) {
poorEdit.loadJson(s);
}
class PoorEdit extends LinearLayout {
private EditView editView;
public PoorEdit(Context context) {
super(context);
initUI();
}
public PoorEdit(Context context, AttributeSet attrs) {
super(context, attrs);
initUI();
}
private void initUI(){
this.setOrientation(VERTICAL);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
this.setLayoutParams(layoutParams);
DisplayMetrics dm = getContext().getResources().getSystem().getDisplayMetrics();
this.setMinimumHeight(dm.heightPixels);
// TODO: 15/11/25 Override OnMeasure in EditView
editView = new EditView(getContext());
this.addView(editView);
((Activity) getContext()).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
public void loadJson(String folderPath){
editView.loadJson(folderPath);
}
public String toJson(String dest){
return editView.toJson(dest);
}
}
And the EditView is -
public class EditView extends FrameLayout implements View.OnDragListener {
public static BaseContainer poorBoy;
private BaseContainer lastAdd = null;
public EditView(Context context) {
super(context);
initUI();
}
public EditView(Context context, AttributeSet attrs) {
super(context, attrs);
initUI();
}
private void initUI(){
this.setOnDragListener(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1);
this.setLayoutParams(layoutParams);
//Call addView to add a EditText in this function.
addTextOn(0, 0, Constants.eleWidth, Constants.eleHeight);
}
}
Add this code inside your <activity> in AndroidManifest.xml
android:windowSoftInputMode="adjustResize|stateHidden"
Related
i have a big problem with creating and removing views in many times
For example i searched in sqlite database and fetching 200 records, and i want create 200view in my activity but it happen in 3 or 4 seconds and it is bad for user experiences and performances.how to increase time for creating views every time?
These are my codes for creating views
public class CreateView {
boolean header_flag=false;
boolean first_widget=false;
LinearLayout header_layout;
List<Words_taha> words_tahaList=new ArrayList<>();
public void createHeader(Context context, LinearLayout main_layout, Words_taha words){
if(header_flag==false){
header_layout =new LinearLayout(context);
header_layout=new LinearLayout(context);
header_layout.setOrientation(LinearLayout.HORIZONTAL);
header_layout.setBackgroundResource(R.mipmap.sure_template);
header_layout.setId(words.getW_id());
header_layout.setGravity(Gravity.CENTER);
main_layout.addView(header_layout);
header_flag=true;
words_tahaList.add(words);
}
else {
words_tahaList.add(words);
Collections.reverse(words_tahaList);
for(int i=0;words_tahaList.size()>i;i++){
TextView textView=new TextView(context);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
textView.setText(words_tahaList.get(i).getW_text()+" ");
textView.setTag(words_tahaList.get(i).getW_id());
Typeface typeface=Typeface.createFromAsset(context.getAssets(),"fonts/arabicNeirizi.ttf");
textView.setTypeface(typeface);
textView.setTextColor(Color.parseColor("#000000"));
header_layout.addView(textView);
}
words_tahaList.clear();
header_flag=false;
}
}
public void createLabelForMainWordsInOneLine(Activity context, LinearLayout main_layout, List<Words_taha> words_tahaList, int count ){
LinearLayout linearLayout=new LinearLayout(context);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.setGravity(Gravity.CENTER);
if(words_tahaList.size()>0) {
main_layout.addView(linearLayout);
Collections.reverse(words_tahaList);
for (Words_taha w : words_tahaList) {
DroidTextView textView = new DroidTextView(context);
textView.setText(w.getW_text());
textView.setTag(w.getW_id());
textView.setTextColor(Color.parseColor("#000000"));
if (w.getW_type() == 3) {
textView.setLayoutParams(new LinearLayout.LayoutParams(130, 130));
textView.setGravity(Gravity.CENTER);
textView.setBackgroundResource(R.mipmap.sore);
} else {
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
}
linearLayout.addView(textView);
}
words_tahaList.clear();
}
}
Please help me how to optimization my code
Thanks.
Well there are a views in android that made for this specific purpose, like ListView or RecyclerView and more, those views get Adapter object, the Adapter restore the data (in your case your 200 rows) and ListView For Example create only the Items That apear in the screen, And when the user scroll up ro down, ListView create the new Views that apear and delete the olds, this give to the user a fantastic use in huge lists of items, I recommend to lern use with ListView and Adapter if you must use your own custom View you can extends from ListView and implemnt in your own way.
you can read more here
if your want specific gui that diffrent from ListView or you need help let me know
Update :
if you want to create your own impl what do you think about this direction ?
public abstract class CustomBookView extends LinearLayout implements CustomBookListener {
private int pageIndex = 0;
private List<WordsTasa> wordsList;
public CustomBookView(Context context, int pageIndex, List<WordsTasa> wordsList) {
super(context);
this.pageIndex = pageIndex;
this.wordsList = wordsList;
}
public abstract View createPage(WordsTasa wordsTasa);
#Override
public void goNextPage() {
if(wordsList.size()>=pageIndex+1)
return;
this.removeAllViews();
//add your animation
this.addView(createPage(wordsList.get(++pageIndex)));
}
#Override
public void goPreviousPage() {
if(0<pageIndex-1)
return;
this.removeAllViews();
//add your animation
this.addView(createPage(wordsList.get(--pageIndex)));
}
public int getPageIndex() {
return pageIndex;
}
public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
}
public List<WordsTasa> getWordsList() {
return wordsList;
}
public void setWordsList(List<WordsTasa> wordsList) {
this.wordsList = wordsList;
}
public CustomBookView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomBookView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public static class WordsTasa {
private String words;
public WordsTasa(String words) {
this.words = words;
}
public String getWords() {
return words;
}
public void setWords(String words) {
this.words = words;
}
}
}
public interface CustomBookListener {
void goNextPage();
void goPreviousPage();
}
on your next page button or previous
button.setOnClickListener(new View.OnClickListener {
public void onClick(View v) {
customBookListener.goNextPage();
}
})
I'm creating a custom TextSwitcher as below
public class CustomTextSwitcher extends TextSwitcher {
private static final long SHOW_TEXT_ANIMATION_TIME = 100;
public CustomTextSwitcher(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
Animation in = AnimationUtils.loadAnimation(context, android.R.anim.fade_in);
Animation out = AnimationUtils.loadAnimation(context, android.R.anim.fade_out);
in.setDuration(SHOW_TEXT_ANIMATION_TIME);
out.setDuration(SHOW_TEXT_ANIMATION_TIME);
this.setInAnimation(in);
this.setOutAnimation(out);
}
public void setStyle(final int style) {
this.setFactory(new ViewSwitcher.ViewFactory() {
#Override
public View makeView() {
return new TextView(new ContextThemeWrapper(context, style),
null, 0);
}
});
}
}
This is good, except I need to explicitly set the style using setStyle function as declared above, after initialization.
I'm hoping that I don't need to call setStyle but just declare my style in XML (as shown in code below) and get the int value through attr value got in constructor, and send it along to the ViewFacory, all done in init() function.
<my.example.CustomTextSwitcher
android:id="#+id/search_list_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/recentSearchHeaderText" />
How could I achieve that?
The AttributeSet you get from the Constructor is generated from the style attribute in XML along with the other attributes provided. So you would just save it then pass it along in the constructor to your TextView.. The setStyle method can actually be used with the TextView#setTextAppearance method which accepts style IDs. It will only look at style attributes that are associated with the TextView. I would say this is easier than parsing through an AttributeSet and creating your own styles.
I found the way to do so. It's as simple as attrs.getStyleAttribute(). Shown the code below
public class CustomTextSwitcher extends TextSwitcher {
private static final long SHOW_TEXT_ANIMATION_TIME = 100;
public CustomTextSwitcher(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(AttributeSet attrs) {
this.setFactory(new ViewFactory() {
#Override
public View makeView() {
return new TextView(new ContextThemeWrapper(context,
attrs.getStyleAttribute()), null, 0);
}
});
Animation in = AnimationUtils.loadAnimation(context, android.R.anim.fade_in);
Animation out = AnimationUtils.loadAnimation(context, android.R.anim.fade_out);
in.setDuration(SHOW_TEXT_ANIMATION_TIME);
out.setDuration(SHOW_TEXT_ANIMATION_TIME);
this.setInAnimation(in);
this.setOutAnimation(out);
}
}
I am trying to create a list view as follows:-
Now, I have made the list view work successfully using the WearableListView adapter. However, I am using static images in the ImageView. What I want is to create this gray and blue kind of animation when a particular list element is focused while scrolling. How do I do that? I tried using a selector xml file for the ImageView but it seems this ListView doesnt make use of this selector(android:state-focused, selected, pressed-nothing works). Any idea how do I get what I want? Hope I made my question clear. Thanks.
Yes you are right, image selector doesn't work, why? I don't know exactly and we don't have any documentation on it to read.
But fortunately I have implemented this scenario successfully and it's almost similar to the default settings screen.
For workaround, I have set circle color inside below methods:
onScaleUpStart() - Set circle color for selected item
onScaleDownStart() - Set circle color for non-selected items.
I have taken CircleImageView and TextView inside my item layout. Example code could be:
private final class MyItemView extends FrameLayout implements WearableListView.Item {
final CircledImageView image;
final TextView text;
private float mScale;
private final int mFadedCircleColor;
private final int mChosenCircleColor;
public MyItemView(Context context) {
super(context);
View.inflate(context, R.layout.wearablelistview_item, this);
image = (CircledImageView) findViewById(R.id.image);
text = (TextView) findViewById(R.id.text);
mFadedCircleColor = getResources().getColor(android.R.color.darker_gray);
mChosenCircleColor = getResources().getColor(android.R.color.holo_blue_dark);
}
#Override
public float getProximityMinValue() {
return mDefaultCircleRadius;
}
#Override
public float getProximityMaxValue() {
return mSelectedCircleRadius;
}
#Override
public float getCurrentProximityValue() {
return mScale;
}
#Override
public void setScalingAnimatorValue(float value) {
mScale = value;
image.setCircleRadius(mScale);
image.setCircleRadiusPressed(mScale);
}
#Override
public void onScaleUpStart() {
image.setAlpha(1f);
text.setAlpha(1f);
image.setCircleColor(mChosenCircleColor);
}
#Override
public void onScaleDownStart() {
image.setAlpha(0.5f);
text.setAlpha(0.5f);
image.setCircleColor(mFadedCircleColor);
}
}
New update brings WearableListView.OnCenterProximityListener alternative of WearableListView.Item to implement Wearable list view with selector,
It has two methods to implement:
onCenterPosition
onNonCenterPosition
public class WearableListItemLayout extends LinearLayout implements WearableListView.OnCenterProximityListener {
private CircledImageView image;
private TextView text;
public WearableListItemLayout(Context context) {
this(context, null);
}
public WearableListItemLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WearableListItemLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
image = (CircledImageView) findViewById(R.id.image);
text = (TextView) findViewById(R.id.name);
}
#Override
public void onCenterPosition(boolean b) {
image.setAlpha(1f);
image.setBackgroundResource(R.drawable.blue_oval);
text.setAlpha(1f);
}
#Override
public void onNonCenterPosition(boolean b) {
image.setAlpha(0.5f);
image.setBackgroundResource(R.drawable.gray_oval);
text.setAlpha(0.5f);
}
}
I am trying to add different views using the relative layout. The edittext and the spinner get added but the listview is not showing .Also, I am not using xmls for layout
public class CustomView extends LinearLayout {
Context rContext;
private String rTitle;
private Spinner rSpinner;
private EditText rInput;
private ListView rResultsList;
public CustomView(Context context) {
super(context);
rContext = context;
}
public CustomView(Context context, AttributeSet attrs, int theme) {
super(context, attrs, theme);
}
public void initialize(String title) {
rTitle = title;
rInput = new EditText(rContext);
rInput.setId(1);
rSpinner = new Spinner(rContext);
rSpinner.setId(2);
rResultsList = new ListView(rContext);
rResultsList.setId(3);
rInput.setText("1");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(rContext, R.layout.result_item, R.id.result_item, new String[] { "this", "that" });
rResultsList.setAdapter(adapter);
addViews();
}
#Override
public String toString() {
return rTitle;
}
private void addViews() {
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(ConvertoActivity.APP_WIDTH / 2, 100);
relativeParams.addRule(RelativeLayout.RIGHT_OF, rInput.getId());
RelativeLayout.LayoutParams relativeParams2 = new RelativeLayout.LayoutParams(ConvertoActivity.APP_WIDTH / 2, 100);
relativeParams.addRule(RelativeLayout.LEFT_OF, rSpinner.getId());
RelativeLayout.LayoutParams relativeParams3 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
relativeParams.addRule(RelativeLayout.BELOW, rInput.getId());
this.addView(rInput, relativeParams2);
this.addView(rSpinner, relativeParams);
this.addView(rResultsList, relativeParams3);
}
}
Your custom view extends LinearLayout and you are using RelativeLayout.Layout params. Change your custom view to extend RelativeLayout.
Nevermind, I found the answer.
I was adding rules to the same object of relative params.
I have following custom button view.
public class PrayerTimeLabel extends Button {
int hours;
int minutes;
String dayHalf; //am or pm
Context parentActivity;
PrayerControl parentControl;
public PrayerTimeLabel(Context context,PrayerControl parent) {
super(context);
init(context,parent,0);
}
public PrayerTimeLabel(Context context, int defStyle, PrayerControl parent) {
//super(context, null, R.style.Button_PrayerTimeButton);
super(context, null, defStyle);
init(context,parent,defStyle);
}
private void init(final Context context, PrayerControl parent, int defStyle)
{
parentActivity = context;
parentControl = parent;
Typeface tf = Typeface.createFromAsset(context.getAssets(),"fonts/digital.ttf");
this.setTypeface(tf);
this.setText(false);
this.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
TimeDialog dialogBox = parentControl.getDialogBox();
dialogBox.setTime(hours, minutes, dayHalf);
dialogBox.show();
}
});
}
public void setTime(int hrs, int min, String half,boolean signalParent)
{
hours = hrs;
minutes = min;
dayHalf = half;
this.setText(signalParent);
}
public void setText(boolean signalParent)
{
super.setText(String.format("%02d", hours)+":"+String.format("%02d", minutes)+" "+dayHalf);
if(signalParent){
parentControl.setPrayerTime(hours, minutes, dayHalf);
}
}
}
and I have the following style defined in my style.xml
<style name="Button.PrayerTimeButton" parent="#android:style/TextAppearance.Widget.Button">
<item name="android:background">#000</item>
<item name="android:textSize">18dp</item>
<item name="android:textColor">#FFFF00</item>
</style>
The extended button is not getting this style. Can some on point our what I am doing wrong? I searched for the solution and found this. Can some one suggest some thing
Note: I cannot use XML to apply styles. It has to be constructor.
Edit:
Following is the class where this custom button is created and used. I have deleted many irrelevant lines of code
public class PrayerControl extends LinearLayout {
protected PrayerTimeLabel prayerTimeButton;
protected String prayerName;
protected static int counter=0;
public PrayerControl(Context context) {
super(context);
init(context);
}
public PrayerControl(Context context, AttributeSet attrs) {
super(context, attrs);
getXMLAttributes(context, attrs);
init(context);
}
protected void getXMLAttributes(Context context, AttributeSet attrs)
{
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.PrayerControl);
prayerName = a.getString(R.styleable.PrayerControl_name);
dayHalf = a.getString(R.styleable.PrayerControl_dayHalf);
hours = a.getInteger(R.styleable.PrayerControl_hours, 4);
minutes = a.getInteger(R.styleable.PrayerControl_minutes, 30);
ltrProgress = a.getInteger(R.styleable.PrayerControl_postNamazInterval, 0);
rtlProgress = a.getInteger(R.styleable.PrayerControl_preNamazInterval, 0);
intervalMax = a.getInteger(R.styleable.PrayerControl_intervalMax, 30);
a.recycle();
}
protected void init(Context context)
{
counter++;
parentActivity = context;
this.setOrientation(LinearLayout.HORIZONTAL);
this.setId(counter);
prayerTimeButtonStyle = R.style.Button_PrayerTimeButton;
initializePrayerTimeButton();
}
protected void initializePrayerTimeButton()
{
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
40);
params.gravity = Gravity.CENTER;
//params.weight = 1.0f;
prayerTimeButton = new PrayerTimeLabel(parentActivity,prayerTimeButtonStyle,this);
prayerTimeButton.setTime(hours, minutes, dayHalf,false);
prayerTimeButton.setLayoutParams(params);
this.addView(prayerTimeButton);
}
}
This is an old answer: I got a -1 a couple of minutes ago and here is the
NEW SOLUTION:
The basic idea is to pass an attribute to the constructor.
Check this link for the complete solution: Applying style to views dynamically in java code
OLD SOLUTION (NOT WORKING):
Add these constructors to your class:
public StyledButton(Context context) {
super(context, null, R.style.Button_PrayerTimeButton);
//... whatever
}
public StyledButton(Context context, AttributeSet attrs) {
super(context, attrs, R.style.Button_PrayerTimeButton);
//... whatever
}
public StyledButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, R.style.Button_PrayerTimeButton);
//... whatever
}
Why not use setTextAppearance(Context context, int resid);. It lets you set the text color, size, style, hint color, and highlight color.
In PrayerTimeLabel class,
private void init(final Context context, PrayerControl parent, int defStyle)
{
setTextAppearance(context, R.style.Button_PrayerTimeButton);
...
}
For more info see this post : setTextAppearance through code referencing custom attribute
Here is an old answer (and simpler) for this topic:
https://stackoverflow.com/a/21455192/4360308
Summarizing:
ContextThemeWrapper newContext = new ContextThemeWrapper(baseContext, R.style.MyStyle);
button = new Button(newContext);
You should make in your constructor a call to the super(context,attrs,defStyle) constructor, which will apply the defStyle to your View.
However you can not than change the style dinamically.
The bug report you link to states:
In addition, when dynamically creating elements at run-time this means that you can't simply apply a style in code. You need to create a separate XML layout for the view you're building, and inflate it [...]
With this in mind, a solution could look like this:
Create an xml layout for your button - let's call it prayertimebutton.xml:
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFF00"
//...etc
/>
Then, in the initializePrayerTimeButton method in your PrayerControl class, inflate and add the PrayerTimeLabel button to the PrayerControl layout:
//Retrieve a LayoutInflater instance that is hooked up to the current context
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//The LayoutInflater instantiates the layout file into a PrayerTimeLabel object
PrayerTimeLabel button = (PrayerTimeLabel)inflater.inflate(R.layout.prayertimebutton, this, false);
//add the PrayerTimeLabel to the PrayerControl
this.addView(button);
Note that the second parameter of LayoutInflater.inflate() is a reference to the parent View(Group).
The below answer by adamp, an Android framework engineer at Google, discusses this approach in more detail.
Why so complex to set style from code in Android