Sorry for not posting any code.
Searching on stackoverflow and google but could not find proper solution for this, so could you please help me out, if you have any idea or tricks for this.
Requirment:
I have many buttons create programmatically according to web's requirement.and set all button's background image with grayscale. I have done this part but when scrolling horizontal scollview then i want to change of that buttons(visible to that time when scrolling) background image colored( initial load grayscaled) and certain time let us assume 10 second buttons background set intial sate(grayscaled).
Main theme:
Change button background image when scolling on visiable view's
button. for cetain time interval(10 second).
`
Problem:
I could not get buttons current visible in horizontal view and change of that buttons background colored image(first time view load). All i want to this programmatically, because all images getting from server side.
Any idea , how could do this job or any references for this task.
Note:
I create button view and set image background and add images on linearlayout and add that linear layout other mainlinearlayout and add mainlinearlayout on horizontalview layout.
sample snipped of my code:
public class CustomAdWithTitle extends LinearLayout{
private LinearLayout LinearCollectionAds;
private List<CommericalClassifiedAds> listCommericalAds;
HorizontalScrollView commercialH = new HorizontalScrollView(mcontext);
commercialH.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
LinearLayout commercialL = new LinearLayout(mcontext);
commercialL.setOrientation(LinearLayout.HORIZONTAL);
commercialL.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
LinearLayout LinearCollectionAds= new LinearLayout(mcontext);
LinearCollectionAds.setOrientation(LinearLayout.VERTICAL);
LinearCollectionAds.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
for (int i = 0; i < listCommericalAds.size(); i++) {
try {
commercialL.addView(listCommericalAds.get(i));
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
commercialH.addView(commercialL);
LinearCollectionAds.addView(commercialH);
this.addView(LinearCollectionAds);
}
...............
list of CommericalClassifiedAds it could return relativelayout with buttonview. i just add button background only and set grayscaled here first time load view.
public class CommericalClassifiedAds extends RelativeLayout {
}
Let's see if I got you right. For changing the image behind buttons you can use a StateListDrawable
StateListDrawable stateList = new StateListDrawable();
stateList.addState(new int[] { android.R.attr.state_selected }, bitmapFromServer);
stateList.addState(new int[] {}, bitmapGrayScale);
Add it to the each CommericalClassifiedAds background when created instead of the buttons background. Register a Scroll listener to commercialH and update UI in it.
private static boolean wait;
private static Handler handler = new Handler();
private static Runnable delayRunnable = new Runnable() {
#Override
public void run() {
int childcount = commercialL.getChildCount();
for (int i=0; i < childcount; i++){
commercialL.getChildAt(i).setSelected(false);
}
};
#Override
public void onScrollChanged() {
//this method can be called very frequently so only run selective
if (!wait) {
handler.removeCallbacks(delayRunnable);
wait = true;
int childcount = commercialL.getChildCount();
for (int i=0; i < childcount; i++){
commercialL.getChildAt(i).setSelected(true);
}
handler.postDelayed(new Runnable() {
#Override
public void run() {
wait = false;
}
}, 2000);
handler.postDelayed(delayRunnable, 10000);
}
}
If it runs slow I would first rethink the layout structure. Looks like you have a couple more layouts than required and then optimize onScroll.
I'm leaving a reservation for errors, it's not tested but it can give you that idea of how to solve your problem.
Related
I have multiple lines of text that I want to add to a LinearLayout. However, I only want to add as many as will fit within the fixed vertical size of the layout.
I'm using onGlobalLayout and getLocalVisibleRect but I can't figure out a way to get the loop to wait for the layout to finish without the latch waiting forever. (I'm sure I just don't understand how the UI thread works.)
Here's what I'm trying:
final LinearLayout content = ((LinearLayout) findViewById(R.id.innerView));
final Rect myRect = new Rect();
TextView lastView = new TextView(this);
for (int i = 0; i < 3; i++) {
final TextView valueTV = new TextView(content.getContext());
final CountDownLatch waitForLayout = new CountDownLatch(1);
valueTV.setText("hallo hallo this is a really long line that might wrap but might not I'm not really sure what will happen");
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(15, 5, 50, 20);
valueTV.setLayoutParams(params);
final ViewTreeObserver textViewTreeObserver = valueTV.getViewTreeObserver();
textViewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
//Do your operations here.
valueTV.getLocalVisibleRect(myRect);
Log.i("New Bottom", String.format("Bottom %d", myRect.bottom));
waitForLayout.countDown();
}
});
content.addView(valueTV);
content.requestLayout();
try {
waitForLayout.await();
}
catch(InterruptedException ie)
{
}
}
I'm more than open to moving anything to a separate method.
You're blocking the completion of onCreate(), which means your first view is never laid out, so the countDown() call is never executed.
The OnGlobalLayoutListener already only runs once the first view is laid out, so move your code into the listener and delete the CountDownLatch altogether.
textViewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
// put your view adding here
}
});
I have to create a large layout in Android programmatically so I want to do it in background.
This layout is a vertical LinearLayout defined in my XML and it will contain a big number of rows.
This is the layout container (defined in my XML):
private LinearLayout gridL;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
gridL = (LinearLayout)_fragment.findViewById(R.id.grid);
...
}
This is the Thread class to populate this layout:
private class CreateGridThread extends Thread {
public void run() {
Looper.prepare();
createGrid();
handler.sendEmptyMessage(101);
}
}
And I call this class this way:
CreateGridThread gridThread = new CreateGridThread();
gridThread.start();
Inside createGrid() I added my components directly to gridL so I get a "CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views." exception.
So, to avoid this I created an auxiliary layout:
private LinearLayout gridLAux;
And I changed my createGrid() so all components were added to this Layout not to gridL. This is my createGrid() method (with some minor editions):
public void createGrid()
{
gridLAux = new LinearLayout(myActivity);
gridLAux.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
gridLAux.setOrientation(LinearLayout.VERTICAL);
LinearLayout currentLayout = null;
int lastIndex = 0;
for(int i = 0; i < myData.size(); i++)
{
Bundle b = myData.get(i);
// Here I read my data
// 3 columns
lastIndex = i % 3;
if(lastIndex == 0)
{
// Container for the whole row
currentLayout = new LinearLayout(myActivity);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
currentLayout.setLayoutParams(params);
currentLayout.setOrientation(LinearLayout.HORIZONTAL);
currentLayout.setWeightSum(3);
gridLAux.addView(currentLayout);
}
// Container for a cell
RelativeLayout rowL = new RelativeLayout(myActivity);
LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
params1.weight = 1;
rowL.setLayoutParams(params1);
rowL.setTag(i);
currentLayout.addView(rowL);
// Container for 2 images
LinearLayout imagesL = new LinearLayout(myActivity);
RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params2.addRule(RelativeLayout.ALIGN_PARENT_TOP);
params2.setMargins(0, 0, 0, 0);
imagesL.setLayoutParams(params2);
imagesL.setOrientation(LinearLayout.HORIZONTAL);
imagesL.setWeightSum(2);
imagesL.setId(R.id.text);
rowL.addView(imagesL);
// Left image
ImageView leftIV = new ImageView(myActivity);
LinearLayout.LayoutParams params3 = new LinearLayout.LayoutParams(
myActivity.getResources().getDimensionPixelSize(R.dimen.img_width),
myActivity.getResources().getDimensionPixelSize(R.dimen.img_height));
params3.weight = 1;
leftIV.setLayoutParams(params3);
leftIV.setAdjustViewBounds(true);
leftIV.setScaleType(ScaleType.FIT_XY);
leftIV.setImageResource(R.drawable.ico_left);
imagesL.addView(leftIV);
// Right image
ImageView rightIV = new ImageView(myActivity);
LinearLayout.LayoutParams params4 = new LinearLayout.LayoutParams(
myActivity.getResources().getDimensionPixelSize(R.dimen.img_width),
myActivity.getResources().getDimensionPixelSize(R.dimen.img_height));
params4.weight = 1;
rightIV.setLayoutParams(params4);
rightIV.setAdjustViewBounds(true);
rightIV.setScaleType(ScaleType.FIT_XY);
rightIV.setImageResource(R.drawable.ico_right);
imagesL.addView(rightIV);
}
if(currentLayout != null)
{
for(int i = 0; i < 2 - lastIndex; i++)
{
LinearLayout imgWrapper = new LinearLayout(myActivity);
LinearLayout.LayoutParams paramsLayoutWrapper = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
paramsLayoutWrapper.weight = 1;
imgWrapper.setLayoutParams(paramsLayoutWrapper);
currentLayout.addView(imgWrapper);
}
}
}
Finally, after the task has ended I call the Handler:
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 101:
gridL.addView(gridLAux);
break;
}
}
};
So, in background I add all my components to an auxiliar layout and in the main thread I add this auxiliar layout to the good one.
But, I'm still getting
"CalledFromWrongThreadException: Only the original thread that created
a view hierarchy can touch its views." exceptions in addView calls
inside createGrid()
. What am I doing wrong?
You always must add views on UI thread, so use Handler on MainLooper
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
gridL.addView(gridLAux);
}
});
Or if you have access to activity you may use Activity's runOnUiThread method
I faced a similar problem creating large dynamic forms and I found that certain UI widgets can only be created from the main thread while other can be created from outside without problem. In my case, there where nested linear layouts including every kind of widgets you could name. My solution was, at the main thread execute the creation loop (like Romadro says) but not every element at once to avoid blocking the UI and allow me to display a processing message to the user in the meantime allowing a responsive UI. Hope it helps.
I see few issues in your code, you should notice them:
You should always create your View in UI thread (because of the sake of synchronization). While I do not see any bigs in your view, you can try to define it in the xml then inflate it.
Your Handler will be in the thread which you call new Handler. Therefore, if you call new Handler in a worker thread -> the handler will be in the worker thread as well. (you can use new Handler(Looper.getMainLooper())) instead)
I see your loop to create a lot of big items, why dont you try RecyclerView? it will boost your layout performance a lot.
What Romadro said is correct, also you can inflate or add views in layout like LinearLayout without blocking UI thread with AsyncTask or Concurrent. Take a look at my answer here : https://stackoverflow.com/a/65741410/12204620 you may get some idea.
I have a LinearLayout with RelativeLayout children. Each RelativeLayout has a background image like a file cabinet. I am trying to animate the drawers dropping down into view one after another with a smooth delay. Everything I have tried plays all animations at once. I have this as my method for animating each drawer:
private void dropAndPause(final RelativeLayout drawer){
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_down);
animation.setStartOffset(750L);
drawer.startAnimation(animation);
}
}, 1200);
}
I have also tried this:
View[] views = new View[] { ... };
// 100ms delay between Animations
long delayBetweenAnimations = 100l;
for(int i = 0; i < views.length; i++) {
final View view = views[i];
// We calculate the delay for this Animation, each animation starts 100ms
// after the previous one
int delay = i * delayBetweenAnimations;
view.postDelayed(new Runnable() {
#Override
public void run() {
Animation animation = AnimationUtils.loadAnimation(context, R.anim.your_animation);
view.startAnimation(animation);
}
}, delay);
}
Instead of View[] views, I used this:
View[] drawers = new View[] {
drawerOne, drawerTwo, drawerThree, drawerFour, drawerFive
};
Which plays, again, all of the animations at once. How can I get each "drawer"/view to slide in one at a time? Also, should I have each view as visibility GONE initially?
If you want to animate the views inside a layout, then it's much easier to use layout animations. Basically, you need to load an animation, create a LayoutAnimationController, set the delay on it, and launch the animation. Here's some sample code.
Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.slide_down);
animation.setStartOffset(750L);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.1F);
viewGroup.setLayoutAnimation(controller);
viewGroup.startLayoutAnimation();
The delay here is set as fraction of the animation duration.
I'd like to use the swipe(onFling) feature of android gestures. I have some adjacent pictures to
chancge into an other picture, in case of swiping.(Just like i demonstrated on the picture)
It should work regardless, which direction the player swipe his/her finger.
Could you give me any link? Or any idea which components should i use?
Since your gesture appears to apply the premise that it must:
Gesture must include all adjacent views.Gesture has a direct linear begginning and endGesture is a single movementGesture does not conflict with other similar gestures
You might want to read on "MotionEvent", and the onTouch listener for views.
A single flag private static View beganOn; on the parent class (I am supposing an Activity). Then:
public void onTouch(View v, MotionEvent m){
if(beganOn!=null){
begaOn = v;
return;
} else {
// Where the view Tag, is an Integer to state what number it is in the sequence.
doSelectionOfViews(beganOn.getTag(),v.getTag());
begaOn = null;
}
}
override the onfling() method of the Gesture Detector. You will be able to get the Swipe direction Under this. Now take two counters for both direction and increment it(i.e count++) in the Right/left swipe and vice versa. Below I am posting the code by which you will be able to create that circular indicator. Whichever you want to make highlighted, You need to pass the index only.
public void updateIndicator(int currentPage) {
image_indicator.removeAllViews();
DotsScrollBar.createDotScrollBar(this, image_indicator, currentPage, 5);
}
Here image_indicator is an linear layout defined in xml.
public static class DotsScrollBar
{
LinearLayout main_image_holder;
public static void createDotScrollBar(Context context,
LinearLayout main_holder, int selectedPage, int count)
{
for (int i = 0; i < count; i++) {
ImageView dot = null;
dot = new ImageView(context);
LinearLayout.LayoutParams vp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
vp.setMargins(8, 8, 8, 8);
dot.setLayoutParams(vp);
if (i == selectedPage) {
try
{
dot.setImageResource(R.drawable.page_hint_pre);
}
catch (Exception e)
{
}
} else
{
dot.setImageResource(R.drawable.page_hint_def);
}
main_holder.addView(dot);
}
main_holder.invalidate();
}
}
Pass the index in the upDateIndicator() method to make that particular incator highlighted.
So in my android app I have a HorizontalScrollView that will display images. All images are downloaded an added to the View before it is avalible to the user. However when it does apear I want each image to animate in seperatly. Ive tried a LayoutTransition object attached to my layout with this code to show the views:
transition = new LayoutTransition();
transition.setStagger(LayoutTransition.APPEARING, 500);
transition.setDuration(1000);
transition.setAnimateParentHierarchy(true);
for (int i = 0; i < mGallery.getChildCount(); i++) {
mGallery.getChildAt(i).setVisibility(View.VISIBLE);
transition.showChild(mGallery, mGallery.getChildAt(i));
}
I have also tried this method using the the AnimationEndListener, and a recursive animateView() method
private void animateView(final int index) {
if (mGallery.getChildAt(index) == null)
return;
final View child = mGallery.getChildAt(index);
final Animation an = AnimationUtils.loadAnimation(mRootView.getContext(), R.anim.slideup);
AnimationEndListener listener = new AnimationEndListener() {
#Override
public void onAnimationEnd(Animation animation) {
animateView(index + 1);
}
};
an.setAnimationListener(listener);
child.setAnimation(an);
child.setVisibility(View.VISIBLE);
an.start();
}
The first method is preferable however it always animates in all my images at the same time. The second method kind of works, however it will apply the animation to the first view and the all subsequent views will appear in sequence without the animation playing.