I want to "Drag and Drop" items from a PopupWindow into the underlying View. The problem now is, when i dismiss the PopupWindow after a long click on an item, the underlying view does not receive any MotionEvents. This problem basically breaks down to delegating MotionEvents between views like in the drag-and-drop-between-views-issue as discussed here. A solution was proposed here but in my case this is not an option. I can't use an overlay view that lies on top of the PopupWindow, can I?
The code below is a simplified version of my problem. I basically have one button that brings up the PopupWindow. On a long click on that PopupWindow it gets dismissed. Now the MotionEvents should be send to the underlying view again, but that does not happen (as you can see in the log output).
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.PopupWindow;
public class PopupWindowDragDropActivity extends Activity implements OnClickListener, OnTouchListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.b1).setOnClickListener(this);
findViewById(R.id.contents).setOnTouchListener(this);
}
#Override
public void onClick(View v) {
final PopupWindow p = new PopupWindow(this);
p.setContentView(new Button(this));
p.setHeight(100);
p.setWidth(100);
p.showAtLocation(findViewById(R.id.contents), Gravity.CENTER, 0, 0);
p.getContentView().setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
v.post(new Runnable() {
#Override
public void run() {
p.dismiss();
}
});
return false;
}
});
}
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("", "Action: " + event);
return true;
}
}
Here is the simple XML layout I use:
<?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:orientation="vertical"
android:id="#+id/contents" >
<Button
android:id="#+id/b1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
Related
I am unable to find the way to create a popup like info window in map . I have to use it to show the three button inside
Yes
later
No
these three options are clickable.
The pop up will show above three button in vertical manner in recycler view . I have created recycler view and pop up view but how to show it like a Tooltip with clickabe
you can use PopupWindow, its starting with API +23
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFBBFFBB" android:orientation="vertical" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:text="Hello My Window" android:textSize="20sp" /> <Button android:id="#+id/button1" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:text="Button" android:textSize="20sp" /> </LinearLayout>
class
package com.example.hellopopupwindow;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.Toast;
public class MainActivity extends Activity {
private Context mContext = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showPopupWindow(view);
}
});
}
private void showPopupWindow(View view) {
// A custom layout, as the display content
View contentView = LayoutInflater.from(mContext).inflate(
R.layout.pop_window, null);
// Set the button click event
Button button = (Button) contentView.findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mContext, "button is pressed",
Toast.LENGTH_SHORT).show();
}
});
final PopupWindow popupWindow = new PopupWindow(contentView,
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true);
popupWindow.setTouchable(true);
popupWindow.setTouchInterceptor(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.i("mengdd", "onTouch : ");
return false;
// It returns true if the words, the touch event will be blocked
// PopupWindow onTouchEvent interception is not called, so click on the external area cannot be dismiss
}
});
// If you do not set the PopupWindow background, both the external region click or Back keys are not dismiss box
// I think there is a bug API
popupWindow.setBackgroundDrawable(getResources().getDrawable(
R.drawable.selectmenu_bg_downward));
// After setting the parameter to show
popupWindow.showAsDropDown(view);
}
}
I am trying to create a sort of a transparent tutorial which appears only
the first time. This is the fragment i have created. How do I add this on top of an existing layout
here's the code for the fragment
import android.app.Fragment;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import in.webblue.nuclity.Activity.Logs.SaveLog;
import in.webblue.nuclity.R;
import static android.content.Context.MODE_PRIVATE;
/**
* Created by Akshay on 15-06-2017.
*/
public class TutorialFragment extends Fragment {
private String Class_Name = "TutorialFragment";
private boolean ranBefore;
View topLevelLayout1;
View topLevelLayout2;
View myView;
String methodName = "onCreateView";
public static TutorialFragment newInstance() {
TutorialFragment f = new TutorialFragment();
return f;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myView = inflater.inflate(R.layout.tutorial_layout, container,
false);
topLevelLayout1=myView.findViewById(R.id.tutorial1);
topLevelLayout2=myView.findViewById(R.id.tutorial2);
if (!isFirstTime()) {
topLevelLayout1.setVisibility(View.INVISIBLE);
topLevelLayout2.setVisibility(View.INVISIBLE);
}
return myView;
}
private boolean isFirstTime()
{
try {
SharedPreferences preferences =
this.getActivity().getSharedPreferences("RanBefore", MODE_PRIVATE);
boolean ranBefore = preferences.getBoolean("RanBefore", false);
if (!ranBefore) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("RanBefore", true);
editor.commit();
topLevelLayout1.setVisibility(View.VISIBLE);
topLevelLayout2.setVisibility(View.INVISIBLE);
topLevelLayout1.setOnTouchListener(new
View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
topLevelLayout1.setVisibility(View.INVISIBLE);
topLevelLayout2.setVisibility(View.VISIBLE);
return false;
}
});
topLevelLayout2.setOnTouchListener(new
View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
topLevelLayout2.setVisibility(View.INVISIBLE);
return false;
}
});
}
}
catch (Exception e){
Log.e(getClass().getName(),"Method Name :"+methodName+ " "+ e.getStackTrace().toString());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
SaveLog.saveLog(getContext(),Class_Name,methodName,e.toString());
}
}
return ranBefore;
}
}
I need to add this on top of an existing layout
I think FrameLayout is the way to go here.
The secret of FrameLayout is how it layouts its children. Although normally designed to contain one item, it will happily stack up other element on top of each other. Thus FrameLayout is essentially a way to manipulate the Z-order of views on the screen
Here a thread about what a FrameLayout can do:
what does FrameLayout do?
So your Layout would look something like this:
<FrameLayout>
<Fragment/>
<LinearLayout>
// here is your normal layout
</LinearLayout>
</>
You could do it the following way.
This is your activity on top of which you need to add the fragment.
<?xml version="1.0" encoding="utf-8"?>
<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"
android:orientation="vertical">
<LinearLayout
android:id="#+id/example_fragment_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
//YOUR LAYOUT
</LinearLayout>
<LinearLayout
android:id="#+id/example_fragment_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="EndFragment">
/*THE FRAGMENT YOU WANT TO SHOW. THE LOGIC TO SHOW THIS FRAGMENT
ONLY ONCE WILL HAVE TO BE IN THE ACTIVITY ON TOP OF WHICH YOU ARE
SHOWING THIS FRAGMENT*/
<fragment
android:id="#+id/example_fragment"
android:name="com.example.ExampleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</RelativeLayout>
Now what you should do is show this fragment only once. The onClick method to hide this fragment is as follows:
public void EndFragment(View view) {
example_fragment_parent.setVisibility(View.GONE);
}
You need to find this fragment in the onCreate() of your activity like below:
LinearLayout example_fragment_parent =
(LinearLayout)findViewById(R.id.example_fragment_parent);
I have a linear layout which contains 5 linear layouts as its child. I want to handle the touch event for each child linear layouts. My layout looks like this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container">
<LinearLayout android:id="#+id/item1"
android:layout_width="match_parent"
style="#style/NavLinkItemContainer"
android:layout_height="wrap_content">
<TextView
style="#style/NaviLinkSelected"
android:text="First"/>
</LinearLayout>
<LinearLayout android:id="#+id/item2"
android:layout_width="match_parent"
style="#style/NavLinkItemContainer"
android:layout_height="wrap_content">
<TextView
style="#style/NaviLinks"
android:text="Second"/>
</LinearLayout>
<LinearLayout android:id="#+id/item3"
android:layout_width="match_parent"
style="#style/NavLinkItemContainer"
android:layout_height="wrap_content">
<TextView
style="#style/NaviLinks"
android:text="Third"/>
</LinearLayout>
<LinearLayout android:id="#+id/item4"
android:layout_width="match_parent"
style="#style/NavLinkItemContainer"
android:layout_height="wrap_content">
<TextView
style="#style/NaviLinks"
android:text="Fourth"/>
</LinearLayout>
<LinearLayout android:id="#+id/item5"
android:layout_width="match_parent"
style="#style/NavLinkItemContainer"
android:layout_height="wrap_content">
<TextView
style="#style/NaviLinks"
android:text="Fifth"/>
</LinearLayout>
</LinearLayout>
and My activity using the layout looks like
public class MainActivity extends Activity implements OnTouchListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("","ON TOUCH VIEW ######## "+v.getId());
return false;
}
}
When touching the child layouts, am not getting id(item1,item2...) in onTouch Event
Please advice.
For each layout you want to add touch listener, set onTouchListener.
for example,
LinearLayout l1 = (LinearLayout) findViewById(R.id.item2);
l1.setOntouchListener(this);
So for each ViewGroup you have to set the listener. The rest of things is already done by your. Int onTouch method you can handle touch or all ViewGroup
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
case R.id.item2:
do something
break;
case R.id.item3:
do something
break;
default:
break;
}
// if you want to consume the behavior then return true else retur false
}
Here is a solution to add an OnTouchListener to every element in the constraint, which will hide the keyboard every time you touch something but an object in the exclusion list.
import android.content.Context;
import android.support.constraint.ConstraintLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.app.AppCompatCallback;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
ConstraintLayout constraintLayout = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText editText = findViewById(R.id.editText);
//Get current ViewGroup. Might have to add an id in the layout xml for the constraint.
constraintLayout = findViewById(R.id.constraint);
//List of items that should be excluded
ArrayList<Integer> listOfExclusion = new ArrayList<>();
listOfExclusion.add(editText.getId());
addTouchListeners(listOfExclusion, constraintLayout);
}
/**
* #param excludedResIds ArrayList of list of ids that should be excluded by the addTouchListener
* #param parent ViewGroup containing the elements you want to lose focus off.
*/
void addTouchListeners(ArrayList<Integer> excludedResIds, ViewGroup parent){
parent.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
constraintLayout.requestFocus();
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
return false;
}
});
addTouchListener(excludedResIds,parent);
}
/**
* #param excludedResIds ArrayList of list of ids that should be excluded by the addTouchListener
* #param parent ViewGroup containing the elements you want to lose focus off.
*/
void addTouchListener(ArrayList<Integer> excludedResIds, ViewGroup parent)
{
for(int index = 0; index<parent.getChildCount(); ++index) {
View nextChild = parent.getChildAt(index);
try{
addTouchListener(excludedResIds, (ViewGroup) nextChild);
}catch (Exception e){
}
if(!excludedResIds.contains(nextChild.getId()))
nextChild.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
constraintLayout.requestFocus();
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
return false;
}
});
}
}
}
I have just copied the official example, and my dialog is very narrow. Why?
My code.
The dialog.
package com.redplanet;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
public class EditNameDialog extends DialogFragment implements OnEditorActionListener {
public interface EditNameDialogListener {
void onFinishEditDialog(String inputText);
}
private EditText mEditText;
public EditNameDialog() {
// Empty constructor required for DialogFragment
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_name, container);
mEditText = (EditText) view.findViewById(R.id.txt_your_name);
getDialog().setTitle("Hello");
// Show soft keyboard automatically
mEditText.requestFocus();
getDialog().getWindow().setSoftInputMode(
LayoutParams.SOFT_INPUT_STATE_VISIBLE);
mEditText.setOnEditorActionListener(this);
return view;
}
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (EditorInfo.IME_ACTION_DONE == actionId) {
// Return input text to activity
EditNameDialogListener activity = (EditNameDialogListener) getActivity();
activity.onFinishEditDialog(mEditText.getText().toString());
this.dismiss();
return true;
}
return false;
}
}
The activity.
package com.redplanet;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.view.Menu;
import android.widget.Toast;
import com.redplanet.EditNameDialog.EditNameDialogListener;
public class FragmentDialogDemo extends FragmentActivity implements EditNameDialogListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showEditDialog();
}
private void showEditDialog() {
FragmentManager fm = getSupportFragmentManager();
EditNameDialog editNameDialog = new EditNameDialog();
editNameDialog.show(fm, "fragment_edit_name");
}
#Override
public void onFinishEditDialog(String inputText) {
Toast.makeText(this, "Hi, " + inputText, Toast.LENGTH_SHORT).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return super.onCreateOptionsMenu(menu);
}
}
Activity layout file.
<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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="#dimen/padding_medium"
android:text="#string/hello_world"
tools:context=".FragmentDialogDemo" />
</RelativeLayout>
Dialog layout file.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/edit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/lbl_your_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Your name" />
<EditText
android:id="#+id/txt_your_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:inputType="text" />
</LinearLayout>
In order not to puzzle over workarounds, I'd prefer an AlertDialog to a DialogFragment. The issue I asked about was on Android 2.3.6 and wasn't on Android 4.1.2.
Project OverView : Theres two images. Click the top image (in my app i use a cat pic) and it will set the bottom image background to the color of the pixel on the location you clicked at.
The Problem: The background color doesn't match the color of the pixel at the location of your click at times its randomly colored, other times its off by a few shades. Its wierd.
This is the main java code :
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.ImageView;
public class ColorRead extends Activity
implements OnTouchListener{
Integer myColor;
String TAG;
Bitmap bMap,bMap2;
ImageView image,image2;
Button BTN;
MotionEvent mEvent;
Integer touchX,touchY;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle Icicle) {
super.onCreate(Icicle);
setContentView(R.layout.main);
bMap = BitmapFactory.decodeResource(getResources(), R.drawable.catpic);
image2 = (ImageView) findViewById(R.id.bitmap2);
image = (ImageView) findViewById(R.id.bitmap);
image.setImageBitmap(bMap);
image.setOnTouchListener(this);
}
public void scanForColor(int xMouse, int yMouse)
{
myColor = bMap.getPixel(xMouse,yMouse);
Log.i(TAG, " R:"+Color.red(myColor)+" G:"+Color.green(myColor)+" B:"+Color.blue(myColor));
image2.setBackgroundColor(myColor);
}
#Override
public boolean onTouch(View v, MotionEvent e) {
Integer id = v.getId();
switch(id)
{
case R.id.bitmap:
if(e.getAction() == MotionEvent.ACTION_DOWN)
{
touchX = (int)e.getX();
touchY = (int)e.getY();
}
scanForColor(touchX,touchY);
Log.i(TAG,touchX.toString());
break;
default:
break;
}
return false;
}
}
Heres the Main.XML :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView android:id="#+id/bitmap"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/catpic"
/>
<ImageView android:id="#+id/bitmap2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="#drawable/catpic"
/>
<Button android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/myButton"
/>
</LinearLayout>