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);
}
}
Related
I'm receiving a series of data from the database and displaying it in a layer that consists of a checkbox and a few other views.In fact, I've made a controlling custom.
My question is how can I turn on the checkbox of that layer when clicked on any layer , and the rest are turned off.
public class myclass extends LinearLayout {
LinearLayout linear;
public int id;
public static ImageView pic;
public static TextView titlepro;
public static CheckBox rdb;
public myclass(Context context) {
super(context);
init(context);
}
public myclass(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public myclass(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void init(Context context){
LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view=inflater.inflate(R.layout.linear,this,true);
linear=(LinearLayout)findViewById(R.id.linear2);
pic=(ImageView)view.findViewById(R.id.pic);
titlepro=(TextView)view.findViewById(R.id.txt1);
rdb=(CheckBox)view.findViewById(R.id.rdb1);
rdb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
}
}
});
linear.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (rdb.isChecked()){
rdb.setChecked(false);
}else {
rdb.setChecked(true);
}
Toast.makeText(G.context,id+"",Toast.LENGTH_LONG).show();
}
});
}}
My problem is that when you click on a layer, the checkbox for the other layer is checked ,but return id correctly.
The issue is because you are using id that is same for all checkboxes.
There can be couple of ways to solve this:
1.linear=(LinearLayout)findViewById(R.id.linear2); -> linear=(LinearLayout)view.findViewById(R.id.linear2);
if that does not work:
2.Consider creating a new fragment, that has all views in a layer. Then you may add multiple of those to your view. In side that class consider handling layer click event.
Use recycler view then you will get index of item clicked and handle from there.
In case you are getting entries from db and you may know how many there might be, your UI may get too heavy. Using recycler view will help with performance
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 want my RelativeLayout to show that it is checked. For this I thought a custom RelativeLayout would be easiest, that would implement checkable. Thus when I clicked an item, this would be called and modify my layout. I thought the easiest would be to highlight it by setBackgroundColor to the holo selected blue.
Firstly is there anything wrong with the above? (i.e. does that sound like a good idea?)
Secondly, it works in that an item will be checked and if I call isChecked it returns the correct answer. However it doesn't update the RelativeLayout to indicate that it is selected. I assume there is something wrong in my code.
public class CustomRL extends RelativeLayout implements Checkable {
private boolean isChecked;
List<RelativeLayout> rl = new ArrayList<RelativeLayout>();
Context context;
public CustomRL(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
#Override
public boolean isChecked() {
return isChecked;
}
#Override
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
for (RelativeLayout r : rl)
r.setBackgroundColor(isChecked ? Color.parseColor("#33b5e5")
: 0x00000000);
}
#Override
public void toggle() {
this.isChecked = !this.isChecked;
for (RelativeLayout r : rl)
r.setBackgroundColor(this.isChecked ? Color.parseColor("#33b5e5")
: 0x00000000);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
final int childCount = this.getChildCount();
for (int i = 0; i < childCount; ++i) {
getRelativeLayout(this.getChildAt(i));
}
}
private void getRelativeLayout(View v) {
if (v instanceof RelativeLayout) {
rl.add((RelativeLayout) v);
}
}
}
This is important to use this layout properly. First of all when You use it in ListView, you should set
listView.setItemsCanFocus(false)
and set choice mode either to
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)
or
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE)
i have a simple question:
suppose i have some views on a scrollView (or a horizontalScrollView) .
is there any way to add a listener that will tell me when such a view is getting inside and outside the visible area ?
the only similar question i've seen is this:
Android: how to check if a View inside of ScrollView is visible?
but i want to be informed when such an event occurs (becoming hidden/visible) .
Subclass the view classes you are using (I did this for ImageView as I was only adding those to my scroll view):
public class PeekImageView extends ImageView implements ViewTreeObserver.OnScrollChangedListener {
private static final String LOG_TAG = "PeekImageView";
private InViewportListener inViewportListener;
private boolean isInViewport = false;
public PeekImageView(Context context) {
super(context);
}
public PeekImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PeekImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public interface InViewportListener {
void onViewportEnter(PeekImageView view);
void onViewportExit(PeekImageView view);
}
public void setInViewportListener(InViewportListener listener) {
this.inViewportListener = listener;
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ViewTreeObserver vto = getViewTreeObserver();
if (vto != null) {
vto.addOnScrollChangedListener(this);
}
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
ViewTreeObserver vto = getViewTreeObserver();
if (vto != null) {
vto.removeOnScrollChangedListener(this);
}
}
#Override
public void onScrollChanged() {
Rect bounds = new Rect();
boolean inViewport = getLocalVisibleRect(bounds);
Log.d(LOG_TAG, "is in view " + bounds + " : " + inViewport + " ; " + bounds);
if (inViewportListener != null && isInViewport != inViewport) {
if (inViewport) {
inViewportListener.onViewportEnter(this);
} else {
inViewportListener.onViewportExit(this);
}
}
isInViewport = inViewport;
}
}
Attaching an InViewportListener to an instance of this PeekImageView will get you notified whenever the view enters or leaves the visible part of the window (the viewport).
You could do something like:
1) keep a list/array of views that are contained in your ScrollView.
2) Set a listener on the scroll view for when the scroll is changed: Synchronise ScrollView scroll positions - android
3) In the listener loop through these views using the Android: how to check if a View inside of ScrollView is visible? method to see if they have gone of the screen
This is a basic method but it'll work, how fast it is depends on whats on your screen etc, but it starts you in the right direction
I've found a nice way to be notified of what i've asked about here.
it works for scrollView with vertical LinearLayout, but if you wish you can make it work for other cases too, depending on the case.
i'm not sure if i should handle onSizeChanged() method too, and if so, what to do there, but in all other cases, this code works fine.
here's the code:
MainActivity.java (for testing) :
public class MainActivity extends Activity
{
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final CustomScrollView scrollView=(CustomScrollView)findViewById(R.id.scrollView1);
scrollView.setOnChildViewVisibilityChangedListener(new onChildViewVisibilityChangedListener()
{
#Override
public void onChildViewVisibilityChanged(final int index,final View v,final boolean becameVisible)
{
Log.d("Applog","index:"+index+" visible:"+becameVisible);
}
});
final ViewGroup container=(ViewGroup)findViewById(R.id.linearLayout);
for(int i=0;i<20;++i)
{
final TextView tv=new TextView(this);
tv.setText("item "+i);
tv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,300));
container.addView(tv);
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.scrollviewvisibilitydetector.CustomScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</com.example.scrollviewvisibilitydetector.CustomScrollView>
</RelativeLayout>
CustomScrollView.java (the real deal...) :
public class CustomScrollView extends ScrollView
{
Set<Integer> _shownViewsIndices =new HashSet<Integer>();
onChildViewVisibilityChangedListener _onChildViewVisibilityChangedListener;
public interface onChildViewVisibilityChangedListener
{
public void onChildViewVisibilityChanged(int index,View v,boolean becameVisible);
}
public CustomScrollView(final Context context)
{
super(context);
}
public CustomScrollView(final Context context,final AttributeSet attrs)
{
super(context,attrs);
}
public CustomScrollView(final Context context,final AttributeSet attrs,final int defStyle)
{
super(context,attrs,defStyle);
}
public void setOnChildViewVisibilityChangedListener(final onChildViewVisibilityChangedListener onChildViewVisibilityChangedListener)
{
_onChildViewVisibilityChangedListener=onChildViewVisibilityChangedListener;
}
#Override
protected void onLayout(final boolean changed,final int l,final int t,final int r,final int b)
{
super.onLayout(changed,l,t,r,b);
checkViewsVisibility(l,t);
}
private void checkViewsVisibility(final int l,final int t)
{
final ViewGroup viewGroup=(ViewGroup)getChildAt(0);
final int childCount=viewGroup.getChildCount();
if(childCount==0)
return;
final int parentBottom=t+getHeight();
// prepare to use binary search to find a view that is inside the bounds
int min=0,max=childCount-1,piv=-1;
int childTop,childBottom;
View v;
// check previously shown views
for(final Iterator<Integer> iterator=_shownViewsIndices.iterator();iterator.hasNext();)
{
final Integer cur=iterator.next();
v=viewGroup.getChildAt(cur);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
{
if(piv==-1)
piv=cur;
}
else
{
if(_onChildViewVisibilityChangedListener!=null)
_onChildViewVisibilityChangedListener.onChildViewVisibilityChanged(cur,v,false);
iterator.remove();
}
}
if(piv==-1)
{
// check first view
v=viewGroup.getChildAt(min);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
piv=min;
else
{
// check last view
v=viewGroup.getChildAt(max);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
piv=min;
}
if(piv==-1)
while(true)
{
piv=(min+max)/2;
v=viewGroup.getChildAt(piv);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t)
break;
if(max-min==1)
return;
if(childBottom<t)
// view above bounds
min=piv;
else max=piv;
}
}
//
for(int i=piv;i<childCount;++i)
{
v=viewGroup.getChildAt(i);
childTop=v.getTop();
childBottom=v.getBottom();
// _shownViewsIndices.
if(childTop<=parentBottom&&childBottom>=t&&!_shownViewsIndices.contains(i))
{
_shownViewsIndices.add(i);
if(_onChildViewVisibilityChangedListener!=null)
_onChildViewVisibilityChangedListener.onChildViewVisibilityChanged(i,v,true);
}
}
for(int i=piv-1;i>=0;--i)
{
v=viewGroup.getChildAt(i);
childTop=v.getTop();
childBottom=v.getBottom();
if(childTop<=parentBottom&&childBottom>=t&&!_shownViewsIndices.contains(i))
{
_shownViewsIndices.add(i);
if(_onChildViewVisibilityChangedListener!=null)
_onChildViewVisibilityChangedListener.onChildViewVisibilityChanged(i,v,true);
}
}
}
#Override
protected void onScrollChanged(final int l,final int t,final int oldl,final int oldt)
{
super.onScrollChanged(l,t,oldl,oldt);
checkViewsVisibility(l,t);
}
}
I have a custom configuration page in my app which just so happens to contain a ListView which you can select/deselect, edit, add to and remove items from. Since the amount of configuration is so large I've had to put it all in a ScrollView
My problem is of course that you cannot have scroll functionality within a view which already has it's own scroll functionality. This means I can't have a scrolling ListView inside a ScrollView.
What I've been trying to do is find the best way of limiting the damage this does. I've seen suggestions that say "You could just create a LinearLayout which grows as you add more children". That would work find by the added effort required to plug in the selectable nature, the reordering & sorting of the list as well as the editing would be a maintanance nightmare.
I've spent the day trying to find a way of measuring the height of each ListView item. Once I can find the size of each item (not just the content but any padding and space between items) on each device I know I can simply change the height of the ListView per item added.
Unfortunately I can't seem to find a way to reliably pull back the height of a listviews child.
(The old chestnut of using a GlobalLayoutListener doesn't help me pull back the padding between items)
final TextView listLabel = (TextView) toReturn.findViewById(R.id.listLabel);
final ViewTreeObserver vto = listLabel.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
listLabel.getViewTreeObserver().removeGlobalOnLayoutListener(this);
mListItemHeight = listLabel.getHeight();
}
});
Maybe you're trying to display too many details on your page? You could split the activity in a summary with buttons that lead to multiple one-screen-long activities.
In my experience, users usually prefer an uncluttered and clear view, even if that means having to click once or twice to get to the part they want.
EDIT
Expanding ListView's are you're friend - This LinearLayout expands based on it's content. It allows Dynamic ListView's inside of ScrollView.
public class LinearListView extends LinearLayout {
private BaseAdapter mAdapter;
private Observer mObserver;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
public LinearListView(Context context) {
super(context);
init();
}
public LinearListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public LinearListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mObserver = new Observer();
}
public void setAdapter(BaseAdapter adapter) {
if (this.mAdapter != null)
this.mAdapter.unregisterDataSetObserver(mObserver);
this.mAdapter = adapter;
adapter.registerDataSetObserver(mObserver);
mObserver.onChanged();
}
public void setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
}
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
}
private int mListSelector = R.drawable.selector_list;
public void setListSelector(int resid) {
mListSelector = resid;
}
private class Observer extends DataSetObserver {
public Observer(){}
#Override
public void onChanged() {
List<View> oldViews = new ArrayList<View>(getChildCount());
for (int i = 0; i < getChildCount(); i++)
oldViews.add(getChildAt(i));
Iterator<View> iter = oldViews.iterator();
removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
final int index = i;
View convertView = iter.hasNext() ? iter.next() : null;
View toAdd = mAdapter.getView(i, convertView, LinearListView.this);
toAdd.setBackgroundResource(mListSelector);
toAdd.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(null, v, index, index);
}
}
});
toAdd.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if(mOnItemLongClickListener != null) {
mOnItemLongClickListener.onItemLongClick(null, v, index, index);
}
return true;
}
});
LinearListView.this.addView(toAdd, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
super.onChanged();
}
#Override
public void onInvalidated() {
removeAllViews();
super.onInvalidated();
}
}
}