Android 片段活动捕获 onKeyDown 并在片段中使用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12210906/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Fragment activity catch onKeyDown and use in fragment
提问by FlorinD
I have Fragment activity with pager:
我有寻呼机的片段活动:
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, PastEventListFragment.class.getName(),bundle));
fragments.add(Fragment.instantiate(this, EventListFragment.class.getName(),bundle));
this.mPagerAdapter = new EventPagerAdapter(super.getSupportFragmentManager(), fragments);
//
ViewPager pager = (ViewPager)super.findViewById(R.id.viewpager1);
pager.setAdapter(this.mPagerAdapter);
pager.setCurrentItem(1);
I catch onKeyDown event :
我抓住了 onKeyDown 事件:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
}
return super.onKeyDown(keyCode, event);
}
The Question is: How to use event in all fragments i have instantiated in this activity . Thanks
问题是:如何在我在此活动中实例化的所有片段中使用事件。谢谢
回答by waqaslam
What you can do is to define a custom method in your fragment class(s). For example:
您可以做的是在片段类中定义自定义方法。例如:
public void myOnKeyDown(int key_code){
//do whatever you want here
}
and call this method whenever a key-down event is raised in your Activity class. For example:
并在您的 Activity 类中引发按键按下事件时调用此方法。例如:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
((PastEventListFragment)fragments.get(0)).myOnKeyDown(keyCode);
((EventListFragment)fragments.get(1)).myOnKeyDown(keyCode);
//and so on...
}
return super.onKeyDown(keyCode, event);
}
回答by PKAP
If someone is interessed how to do it with Boradcast:
如果有人对如何使用 Boradcast 感兴趣:
In your fragment in onViewCreated
在 onViewCreated 的片段中
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Register to receive messages.
// We are registering an observer (mMessageReceiver) to receive Intents
// with actions named "custom-event-name".
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("activity-says-hi"));
...}
// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
doSomethingCauseVolumeKeyPressed();
}
};
your keyevent - code to put in activity
您的关键事件 - 投入活动的代码
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
if (action == KeyEvent.ACTION_DOWN) {
sendBroadcast();
}
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (action == KeyEvent.ACTION_DOWN) {
sendBroadcast();
}
return true;
default:
return super.dispatchKeyEvent(event);
}
}
your broadcast sender:
您的广播发件人:
private void sendVolumeBroadcast(){
Intent intent = new Intent("activity-says-hi");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
回答by kjellhaaland
As mentioned by others, the accepted answer results in tight coupling between the activity and its fragments.
正如其他人所提到的,接受的答案导致活动与其片段之间的紧密耦合。
I would suggest using some sort of event-based implementation instead. This is much more reusable and results in a better software architecture. In previous projects I have used one of the following solutions (Kotlin):
我建议改用某种基于事件的实现。这更具可重用性,并产生更好的软件架构。在以前的项目中,我使用了以下解决方案之一(Kotlin):
Broadcasts
广播
Using Android′s LocalBroadcastManager: Documentation
使用 Android 的 LocalBroadcastManager:文档
Create a BroadcastReceiver:
创建一个广播接收器:
class SomeBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val keyCode = intent?.getIntExtra("KEY_CODE", 0)
// Do something with the event
}
}
}
In your activity:
在您的活动中:
class SomeActivity : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
val intent = Intent("SOME_TAG").apply { putExtra("KEY_CODE", keyCode) }
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
return super.onKeyDown(keyCode, event)
}
}
Then, in any of the fragments (or services, etc..):
然后,在任何片段(或服务等)中:
class SomeFragment : Fragment() {
val receiver = SomeBroadcastReceiver()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val filter = IntentFilter().apply { addAction("SOME_TAG") }
LocalBroadcastManager.getInstance(context!!).registerReceiver(receiver, filter)
return super.onCreateView(inflater, container, savedInstanceState)
}
}
EventBus
事件总线
Using EventBus
使用事件总线
Create an event class:
创建事件类:
data class Event(val keyCode: Int)
In your activity:
在您的活动中:
class SomeActivity : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
EventBus.getDefault().post(Event(keyCode))
return super.onKeyDown(keyCode, event)
}
}
Then, in your fragment:
然后,在您的片段中:
class SomeFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Register for events
EventBus.getDefault().register(this)
return super.onCreateView(inflater, container, savedInstanceState)
}
@Subscribe
public fun onKeyEvent(event : Event) {
// Called by eventBus when an event occurs
}
override fun onDestroyView() {
super.onDestroyView()
EventBus.getDefault().unregister(this)
}
}
回答by dnhyde
Following @hsu.tw answer to avoid tight coupling I found this gist.
按照@hsu.tw 的回答以避免紧耦合,我发现了这个要点。
Avoiding tight coupling comes with a price: you need a focusable view (luckily it was my case since I already had a view in foreground that listens to other touch events, so I just added the View.OnKeyListener
to it).
避免紧密耦合是有代价的:你需要一个可聚焦的视图(幸运的是这是我的情况,因为我已经在前台有一个可以监听其他触摸事件的视图,所以我只是添加了View.OnKeyListener
它)。
The steps needed to attach a View.OnKeyListener
to a view in a Fragment independently of the Activity are (check the gist):
View.OnKeyListener
独立于 Activity将 a 附加到 Fragment 中的视图所需的步骤是(检查要点):
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(pressKeyListener);
I implemented this in the onViewCreated
callback of my Fragment
我在onViewCreated
Fragment的回调中实现了这个
回答by hsu.tw
I have the same problem in developing Android TV app.
我在开发 Android TV 应用时遇到了同样的问题。
And I solve this problem like this:
我是这样解决这个问题的:
In onCreateView method, I call "requestFocus" by some View. (I mark it as ViewA.) Then I set KeyEventListener to ViewA.
在 onCreateView 方法中,我通过一些视图调用“requestFocus”。(我将其标记为 ViewA。)然后我将 KeyEventListener 设置为 ViewA。
In your case, you should do it (set-KeyEventListener) in Adapter and PagerChangeListener.
在您的情况下,您应该在 Adapter 和 PagerChangeListener 中执行此操作(set-KeyEventListener)。
回答by 0neel
I've subclassed Activity and Fragment classes to perform KeyEvents passing. For me, it looks clearer than sending local broadcasts. But this solution can be not so flexible. Choose the preferred way by yourself.
我已经将 Activity 和 Fragment 类子类化来执行 KeyEvents 传递。对我来说,它看起来比发送本地广播更清晰。但是这个解决方案可能没有那么灵活。自行选择首选方式。
Here is the activity:
这是活动:
public abstract class KeyEventPassingActivity extends Activity {
public interface KeyEventListener extends View.OnKeyListener {
boolean isVisible();
View getView();
}
private final List<KeyEventListener> keyEventHandlerList = new ArrayList<>();
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
for (KeyEventListener handler : keyEventHandlerList) {
if (handleKeyEvent(handler, event)) {
return true;
}
}
return super.dispatchKeyEvent(event);
}
void addKeyEventHandler(@NonNull KeyEventListener handler) {
keyEventHandlerList.add(handler);
}
void removeKeyEventHandler(@NonNull KeyEventListener handler) {
keyEventHandlerList.remove(handler);
}
/**
* @return <tt>true</tt> if the event was handled, <tt>false</tt> otherwise
*/
private boolean handleKeyEvent(@Nullable KeyEventListener listener, KeyEvent event) {
return listener != null
&& listener.isVisible()
&& listener.onKey(listener.getView(), event.getKeyCode(), event);
}
}
And the fragment:
和片段:
public abstract class KeyEventHandlingFragment extends Fragment
implements KeyEventPassingActivity.KeyEventListener {
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof KeyEventPassingActivity) {
((KeyEventPassingActivity) activity).addKeyEventHandler(this);
}
}
@Override
public void onDetach() {
Activity activity = getActivity();
if (activity instanceof KeyEventPassingActivity) {
((KeyEventPassingActivity) activity).removeKeyEventHandler(this);
}
super.onDetach();
}
}
Gist: https://gist.github.com/0neel/7d1ed5d26f2148b4168b6616337159ed
要点:https: //gist.github.com/0neel/7d1ed5d26f2148b4168b6616337159ed