I have a linear layout which holds inner (child) custom image view.
My goal is to set a background selector on the image view, and also set a listener
to the linear layout.
however, I can't make the selector and the listener work together.
I don't know how to handle the events.
If I make a quick tap it is working, but If I drag my finger on the views, the image view
remains in selected state.
Here's the activity which has a reference to the linear layout and its listener.
public class EventDispatchingDemoActivity extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout linearLayout = (LinearLayout) findViewById(R.id.my_layout);
linearLayout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
Toast.makeText(getBaseContext(), "Click", Toast.LENGTH_SHORT).show();
}
});
}
}
Here's the custom view (Its a code I found somewhere, credits for the author)
public class ImageSelector extends ImageView
{
public ImageSelector(Context context, AttributeSet attrs)
{
super(context, attrs);
setBackgroundDrawable(new NavStateListDrawable(getContext(), 0));
setClickable(true);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
return false;
}
public class NavStateListDrawable extends StateListDrawable
{
private int level;
public NavStateListDrawable(Context context, int level)
{
this.level = level;
// int stateChecked = android.R.attr.state_checked;
int stateFocused = android.R.attr.state_focused;
int statePressed = android.R.attr.state_pressed;
int stateSelected = android.R.attr.state_selected;
addState(new int[] { stateSelected }, context.getResources().getDrawable(R.drawable.slide_feedback));
addState(new int[] { statePressed }, context.getResources().getDrawable(R.drawable.slide_feedback));
addState(new int[] { stateFocused }, context.getResources().getDrawable(R.drawable.slide_feedback));
addState(new int[] { -stateFocused, -statePressed, -stateSelected }, context.getResources().getDrawable(android.R.color.transparent));
}
#Override
protected boolean onStateChange(int[] stateSet)
{
boolean nowstate = super.onStateChange(stateSet);
try
{
LayerDrawable defaultDrawable = (LayerDrawable) this.getCurrent();
LevelListDrawable bar2 = (LevelListDrawable) defaultDrawable.findDrawableByLayerId(R.id.element_contact_image_selector);
bar2.setLevel(level);
}
catch (Exception exception)
{
}
return nowstate;
}
}
}
And Here's the xml:
<?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:background="#acf1fa"
android:gravity="center"
android:orientation="vertical" >
<!-- outer layout -->
<LinearLayout
android:id="#+id/my_layout"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#00ff00"
android:gravity="center" >
<!-- inner layout -->
<dor.event.dispathing.ImageSelector
android:id="#+id/inner_layout"
android:layout_width="150dp"
android:layout_height="150dp" />
</LinearLayout>
</LinearLayout>
I Uploaded the source:
http://www.filefactory.com/file/5ikfwyk9j5bx/n/EventDispatchingDemo.rar
Thanks in advance for your help!
I remember having a similar issue when I was writing my application.
1) Are you trying to capture if a row in your listview is clicked? I think you want `listView.setonItemClickListener' which will capture clicks for each individual row as opposed to the entire listview.
2) I believe when you have a listview with clickable items inside it, the clickable items inside it take priority in terms of capturing clicks. More than taking priority, I believe they block any click events from being sent back to the parent's event handlers.
I believe a somewhat working solution is to set the focusability of those clickable items to false. Once those clickable items are not longer focusable, the listview row will get focus back. The other solution is to work with the descendantFocusability property which controls who (Entire row or Image) gets first crack and picking up events triggered within the row. Here are some other questions that seem to have what you need:
How to fire onListItemClick in Listactivity with buttons in list?
Android ListView with clickable items in it's rows causes problems continuing scrolling
Related
I'm currently developing an Android App, using a personal SurfaceView and double buffering. However I'm facing a little problem with my code.
In one hand I have an xml view, based on LinearLayout hierarchy. When I instantiate my activity, I set my contentView on this xml. The problem is then that my double buffering don't works anymore. Thread is running but nothing is displayed.
In the other hand, I set my contentView with a new personal SurfaveView element and display works fine. But of course, I cannot access anymore to the other elements of my LinearLayout.
Actually, I would like to set my contentView on my xml view AND keep my display working.
I hope I was clear enough, thank you for your answers!
Here is my activity:
public class MainController extends Activity {
#Override
protected void onCreate(final Bundle p_savedInstanceState) {
super.onCreate(p_savedInstanceState);
setContentView(R.layout.main_controller_activity);
this.drawableView = (MCustomDrawableView) findViewById(R.id.drawingBox);
...
}
...
}
My surface view:
public class MCustomDrawableView extends SurfaceView {
public MCustomDrawableView(Context p_context, AttributeSet p_attributes) {
super(p_context, p_attributes);
this.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(final SurfaceHolder p_holder) {
try {
// Instantiating a new thread
thread = new MBufferingThread(getInstance());
thread.start();
} catch (Exception exception) {
exception.printStackTrace();
}
}
#Override
public void surfaceChanged(final SurfaceHolder p_holder, int p_format, int p_width, int p_height) {...}
#Override
public void surfaceDestroyed(final SurfaceHolder p_holder) {...}
});
// Setup drawing options
setupDrawing();
}
...
}
And my xml view:
<LinearLayout 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"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
android:background="#color/app_background"
tools:context=".MainController">
<com.iskn.calligraphy.models.draw.MCustomDrawableView
android:id="#+id/drawingBox"
style="#style/DrawingBox" />
<SeekBar
android:id="#+id/brushSize"
style="#style/SizeSeekBar" />
<SeekBar
android:id="#+id/brushOpacity"
style="#style/OpacitySeekBar" />
</LinearLayout>
EDIT:
After further researches and analyses, it appears clearly that:
setContentView(R.layout.main_controller_activity): in this case I get all the elements from my activity, but the MCustomDrawableView display nothing.
setContentView(new MCustomDrawableView(getApplicationContext())): on that case, MCustomDrawableView is working well (it displays what I want), but I don't have the others View from my main_controller_activity
In both cases:
my thread is running and works well.
my drawing function is called as well, with the holder.lockCanvas() and holder.unlockCanvasAndPost(bufferCanvas) methods.
Well, I found a functionnal solution :
I think the problem was coming from the MCustomDrawableView initialization . I created a new instance of that class from the onCreate method , and not from the xml file . Then, I set it to the contentView:
protected void onCreate(Bundle p_savedInstanceState) {
super.onCreate(p_savedInstanceState);
setContentView(R.layout.main_controller_activity);
// Instantiate drawable object & set style properties
this.drawableView = new MCustomDrawableView(getApplicationContext());
FrameLayout.LayoutParams style = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
// Add the drawable view to the main_activity
addContentView(this.drawableView, style);
}
But this way raises a new problem. The added view is on the top, which means that all the others View are hided. I solved this with bringToBack(this.drawableView) below method:
private void bringToBack(View p_view) {
// Get parent from the current view
ViewGroup viewGroup = ((ViewGroup) p_view.getParent());
int childrenCount = viewGroup.indexOfChild(p_view);
for(int cpt = 0; cpt < childrenCount; cpt++) {
// Move the child to the top
viewGroup.bringChildToFront(viewGroup.getChildAt(cpt));
}
}
It brings back the provided view to the background position. I also had to set the LinearLayout's alpha to 0.
I'm still open to other solutions!
I'm trying to rotate a ListView inside of a custom popupWindow. Below is my setup:
Here is the popup XML, board_dialog.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/boardll"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ListView
android:id="#+id/boardoptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="#array/options_array_board" />
</RelativeLayout>
My custom BoardPopup class:
public class BoardPopup extends PopupWindow {
private static final String TAG = BoardPopup.class.getSimpleName();
Context context;
RelativeLayout ll;
ListView lv;
private OnSubmitListener mListener;
public BoardPopup (Context ctx, OnSubmitListener listener) {
super(ctx);
context = ctx;
mListener = listener;
setContentView(LayoutInflater.from(context).inflate(R.layout.board_dialog, null));
setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
View popupView = getContentView();
setFocusable(true);
lv = (ListView) popupView.findViewById(R.id.boardoptions);
ll = (RelativeLayout) popupView.findViewById(R.id.boardll);
}
public void show(View v) {
showAtLocation(v, Gravity.CENTER, 0, 0);
}
public interface OnSubmitListener {
void valueChanged(String name, String number);
}
public void fixDimensions() {
getContentView().setBackgroundColor(Color.RED); //to highlight views
ll.setRotation(90);
update(292,630); //These numbers are not meant to be constant
}
}
In my activity, showing the popup and I have to override onWindowFocusChanged in order to get post-drawn dimensions for the views inside the popup:
popup = new BoardPopup(c, MainGamePanel.this);
popupJustCreated = true;
popup.show(v);
.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (popup!=null && popupJustCreated) {
popup.fixDimensions();
popupJustCreated = false;
}
}
If I comment out ll.setRotation(90); and update(292,630); in fixDimensions() then everything looks normal:
If I add in the ll.setRotation(90);:
Finally, if I add in the update(292,630);:
In the final image, why does the layout not fill the popup? What view is that gray area? How can I get this to rotate and resize normally?
Some other things I've tried with no success:
Using LinearLayout instead of RelativeLayout
all different combinations of wrap_content and match_parent
Doing basically the same thing with a custom DialogFragment
I had a very similar issue and just found a workaround. I was using the view rotationX property to rotate items within a RecyclerView and kept seeing strange clipping behaviour like the images above. What worked for me was calling setLayerType on the parent view (a RecyclerView in my case) with the following arguments:
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
The default layer type is is LAYER_TYPE_HARDWARE for API >= 14). By the nature of this work around I'd say this is an Android bug.
I've designed a GridView with custom item layout and there is one ImageView on the top-left corner, another ImageView on the top-right corner, a main ImageView and Text in the center.
I need to set the OnClickListener for both two ImageView on the corner and the OnItemClickListener for the adapter.
Everything worked fine but only the first item in the GridView can't trigger the OnClickListener. Can anyone solve this problem?
P.S. I found the first item ImageView's OnClickListener will trigger when I do the next action(e.g. Click other items)
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
TagView tag;
if (convertView == null) {
v = m_LayoutInflater.inflate(R.layout.mydoc_grid_item, null);
tag = new TagView(
(ImageView) v.findViewById(R.id.myDoc_GridItem_IV),
(TextView) v.findViewById(R.id.myDoc_GridItem_TV),
(ImageView) v.findViewById(R.id.iViewAdd2Category),
(ImageView) v.findViewById(R.id.iViewDelete));
v.setTag(tag);
} else {
tag = (TagView) v.getTag();
}
v.setLayoutParams(new GridView.LayoutParams((int) (180 * v
.getResources().getDisplayMetrics().density), (int) (180 * v
.getResources().getDisplayMetrics().density)));
tag.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
tag.image.setImageDrawable(new BitmapDrawable(BitmapFactory.decodeFile(m_DisplayItems.get(position)
.get("image").toString())));
tag.text.setText(m_DisplayItems.get(position).get("text").toString());
tag.iAdd2Category.setVisibility((m_IsEdit) ? View.VISIBLE : View.GONE);
tag.iDelete.setVisibility((m_IsEdit) ? View.VISIBLE : View.GONE);
if (m_IsEdit) {
tag.iAdd2Category.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i(LOG_TAG, "Click on image add 2 category");
}
});
tag.iDelete.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.i(LOG_TAG, "Click on image delete");
}
});
}
return v;
}
Mixing OnClickListeners and OnItemClickListeners for list's items doesn't work well.
In your case you should probably use multiple OnClickListeners on the different parts of your item and not use OnItemClickListener at all.
I finally found the answer in this article.
OnClickListener not working for first item in GridView
In my case:
if (convertView == null) {
v = m_LayoutInflater.inflate(R.layout.mydoc_grid_item, null);
tag = new TagView(
(ImageView) v.findViewById(R.id.myDoc_GridItem_IV),
(TextView) v.findViewById(R.id.myDoc_GridItem_TV),
(ImageView) v.findViewById(R.id.iViewAdd2Category),
(ImageView) v.findViewById(R.id.iViewDelete));
v.setTag(tag);
} else {
tag = (TagView) v.getTag();
}
just remove if else statement and the "tag" will be instantiated every time.
The reason for this problem is, that Android calls getView() for the first item not only when the View is drawn, but also for Layout-Measuring! There is no way to differ within getView() between a measure call and a draw call. So when you first have a draw call, and at some later point a measure call you overwrite the onClickListener.
Actually it seems right to do so - since you do it every time, but i observed this behaviour. Maybe you set the clickListener and the system releases it after the getView call because the view won't be drawn... I didn't track that deep enough to assure.
Nevertheless it is a bad idea to recreate the view every time since it is VERY time expensive - your grid might not scroll smooth.
The solution is to write your own GridView as follows:
public class MyGridView extends GridView{
private GridAdapter adapter;
public MyGridView(Context context) {
super(context);
}
public MyGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setAdapter(GridAdapter adapter) {
this.adapter = adapter;
super.setAdapter(adapter);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(adapter!=null)
adapter.setIsMeasureCall();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}}
and implement the method setIsMeasureCall() in your GridAdapter. The method only sets a flag to true whenever it is called.
Then in your getView() method you check if it is a measure call and if this is true - you do not set the Listeners.
Make sure to set isMeasure to false at the end of your getView() method.
I hope everything is clear :)
For more information you can check out my homepage where I provide a full Android project that solves this problem.
http://simon.osim.at/projects/gridadapter/#TheSolution
the selector file
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="#drawable/gridview_item_shape"></item>
<item android:state_pressed="false" android:drawable="#android:color/transparent"></item>
</selector>
the item layout file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/griditem"
android:padding="2dp"
android:src="#drawable/grid_photo"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/gridview_item_select"
/>
</RelativeLayout>
I wish to disable all the touch screen interactions while an animation is being displayed.
I don't wish to use the setClickable() method on the buttons at the start or end of the animation because there are a large number of buttons. Any suggestions?
In your Activity, you can override onTouchEvent and always return true; to indicate you are handling the touch events.
You can find the documentation for that function there.
Edit Here is one way you can disable touch over the whole screen instead of handling every view one by one... First change your current layout like this:
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
< .... put your current layout here ... />
<TouchBlackHoleView
android:id="#+id/black_hole"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
And then define your custom view with something like this:
public class TouchBlackHoleView extends View {
private boolean touch_disabled=true;
#Override
public boolean onTouchEvent(MotionEvent e) {
return touch_disabled;
}
public disable_touch(boolean b) {
touch_disabled=b;
}
}
Then, in the activity, you can disable the touch with
(TouchBlackHoleView) black_hole = findViewById(R.id.black_hole);
black_hole.disable_touch(true);
And enable it back with
black_hole.disable_touch(false);
Easy way to implement that is add transaperent layout over it (add it in your xml fill parent height and width).
In the animation start: transaparentlayout.setClickable(true);
In the animation end: transaparentlayout.setClickable(false);
answer to this issue
for (int i = 1; i < layout.getChildCount(); i++) {
TableRow row = (TableRow) layout.getChildAt(i);
row.setClickable(false);
selected all the rows of the table layout which had all the views and disabled them
Eventually I took as a basic answer of #Matthieu and make it work such way. I decide to publish my answer because it take me maybe 30 min to understood why I got error.
XML
<...your path to this view and in the end --> .TouchBlackHoleView
android:id="#+id/blackHole"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Class
public class TouchBlackHoleView extends View {
private boolean touchDisable = false;
public TouchBlackHoleView(Context context) {
super(context);
}
public TouchBlackHoleView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TouchBlackHoleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return touchDisable;
}
public void disableTouch(boolean value){
touchDisable = value;
}
}
Using
blackHole = (TouchBlackHoleView) findViewById(R.id.blackHole);
blackHole.disableTouch(true);
Enjoy
I'm trying to create a gallery in my Android project, but can't seem to make it work as it should.
Here is what I am trying to do:
Basically, I want a gallery that displays only one picture, but still has the same controls (sliding left and right). I'm getting the pictures asynchronously from the internet.
Where am I at that?
Well, for now I'm just trying to display the gallery... I'll see the "one picture" step after.
What is my problem?
Well... My gallery doesn't show on my layout. At all.
What seems to be the problem?
Log information give me that the height and the widht of my gallery object are... 0.
Speaking about code...
Layout.xml
<?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:background="#drawable/fond">
<ImageView android:background="#drawable/banniere" android:layout_height="wrap_content" android:layout_width="fill_parent"/>
<Gallery
android:id="#+id/gallery"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.galleryfullscreen);
Gallery gal = (Gallery) findViewById(R.id.gallery);
ArrayList<Photo> photos = (ArrayList<Photo>) this.getIntent().getExtras().getSerializable("Photos");
int pos = this.getIntent().getExtras().getInt("Index");
Log.i("Season",photos.toString());
gal.setAdapter(new PhotoAdapter(this, photos, false));
gal.setSelection(pos);
Log.d("Bottom", String.valueOf(gal.getBottom()));
Log.d("Right", String.valueOf(gal.getRight()));
Log.d("Width", String.valueOf(gal.getWidth()));
Log.d("Height", String.valueOf(gal.getHeight()));
}
Extras are correctly set.
Adapter
public class PhotoAdapter extends BaseAdapter {
private ArrayList<PhotoView> views;
private ArrayList<Photo> season;
public PhotoAdapter(Context c, ArrayList<Photo> images, boolean mini) {
season = images;
views = new ArrayList<PhotoView>();
for (int i = 0; i < images.size() ; i++)
if (mini)
views.add(new PhotoView(c,images.get(i).getUrlMini(),false));
else{
views.add(new PhotoView(c,images.get(i).getUrlBig(),true));
}
}
#Override
public int getCount() {
return views.size();
}
#Override
public Object getItem(int position) {
return views.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return views.get(position);
}
public ArrayList<Photo> getSeason() {
return season;
}
}
This adaptor is working fine for other objects (such as gridview)
And the PhotoView...
public class PhotoView extends ImageView {
Bitmap image;
public PhotoView(Context context, String url, boolean Gallery) {
super(context);
if (!Gallery){
this.setLayoutParams(new GridView.LayoutParams(GridView.LayoutParams.WRAP_CONTENT,GridView.LayoutParams.WRAP_CONTENT));
this.setScaleType(ImageView.ScaleType.FIT_CENTER);
this.setImageDrawable((getResources().getDrawable(R.drawable.blk)));
new DownloadImageTask().execute(url);
}
else{
this.setLayoutParams(new Gallery.LayoutParams(100,100));
this.setScaleType(ImageView.ScaleType.FIT_CENTER);
this.setBackgroundDrawable(((getResources().getDrawable(R.drawable.blk))));
this.setImageDrawable((getResources().getDrawable(R.drawable.blk)));
}
}
public Bitmap getImage(){
return image;
}
public void setImage(Bitmap img){
image = img;
this.setImageBitmap(image);
}
The same, it's working fine for a grid view. With the download task, that is not set up for the Gallery yet. I'm at least trying to display a ressource before setting this up, so I'm sure the problem doesn't come from here.
Sooo... why are my logs showing "0" for gallery width and height? LayoutParams are set for the object (I tried both XML and code), and for the views inside. The items are created, and the "getView" method is called. I tried seeting up LayoutParams here, doesn't change anything.
I also tried adding the xmlns:android="http://schemas.android.com/apk/res/android" part in the layout for the gallery, doesn't change a thing.
I really don't know what I'm missing. I tried to adapt many tutorials on gallery objects, but still... don't know!
If you have any idea of what I should do/try, please...
Thanks all!
Cheers
Looking at your XML file I can see what could be problem. Your LinearLayout is set to add views in an horizontal matter (that is default) and your first view has its layout_width set to fill_parent.
Set orientation to vertical in your LinearLayout.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#drawable/fond">