WebView allows you to display web content in your activity layout or Fragment but lacks some of the features of fully-developed browsers. A WebView is useful when you need to increase control over the UI and advanced configuration options that will allow you to embed web pages in a specially-designed environment for your app.
Note: To know more about WebView please refer to Android WebView in Kotlin or How to Use WebView in Android. In this article, we will see how we can search keywords(texts) inside a WebView using both Java and Kotlin.
A sample video is given below to get an idea about what we are going to do in this article.
Class Hierarchy
Java:
java.lang.Object
↳ android.view.View
↳ android.view.ViewGroup
↳ android.widget.AbsoluteLayout
↳ android.webkit.WebView
Kotlin:
kotlin.Any
↳ android.view.View
↳ android.view.ViewGroup
↳ android.widget.AbsoluteLayout
↳ android.webkit.WebView
Step by Step Implementation
Step 1: Create a new project in Android Studio
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio.
Step 2: Add Permissions in the AndroidManifest.xml File
In order to access the internet we have to add Internet permission in the AndroidManifest.xml file.
<uses-permission android:name=”android.permission.INTERNET” />
Step 3: Working with the activity_main.xml file
Navigate to app > res > layout > activity_main.xml and add the below code to it. Comments are added in the code to get to know in detail.
XML
<? xml version = "1.0" encoding = "utf-8" ?> < androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context = ".MainActivity" > <!-- Web-view on the Screen --> < WebView android:id = "@+id/webView" android:layout_width = "match_parent" android:layout_height = "match_parent" /> <!--ProgressBar for loading indicator--> < ProgressBar android:id = "@+id/progressBar" style = "?android:attr/progressBarStyle" android:layout_width = "wrap_content" android:layout_height = "wrap_content" app:layout_constraintBottom_toBottomOf = "parent" app:layout_constraintEnd_toEndOf = "parent" app:layout_constraintStart_toStartOf = "parent" app:layout_constraintTop_toTopOf = "@+id/webView" /> </ androidx.constraintlayout.widget.ConstraintLayout > |
Step 4: Adding menu items in the Menu Resource file
In order to know what is menu items or how to add menu items please refer to Android Menus and How to Create Menu Folder & Menu File in Android Studio?
XML
<? xml version = "1.0" encoding = "utf-8" ?> <!--Search menu item--> < item android:id = "@+id/itemSearch" android:icon = "@drawable/ic_search_24" android:title = "Search" app:actionViewClass = "androidx.appcompat.widget.SearchView" app:showAsAction = "always|collapseActionView" /> <!--make sure you add the collapseActionView in showsAsAction--> <!--menu item to jump to next keyword--> < item android:id = "@+id/itemNext" android:icon = "@drawable/ic_arrow_down_24" android:title = "Next Item" android:visible = "false" app:showAsAction = "always" /> <!--menu item to jump to previous keyword--> < item android:id = "@+id/itemPrevious" android:icon = "@drawable/ic_arrow_up_24" android:title = "Previous Item" android:visible = "false" app:showAsAction = "always" /> </ menu > |
Step 5: Working with the MainActivity file
Navigate to app > java > your app’s package name > MainActivity file and add the below code to it. Comments are added in the code to get to know in detail.
Note: In the below code ViewBinding is used in order to reduce the boilerplate code and generated instances of the views of the current layout. This replaces the use of findViewById(). To know more about ViewBinding and how to enable ViewBinding please refer to View Binding in Android Jetpack.
Kotlin
import android.annotation.SuppressLint import android.graphics.Bitmap import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View import android.webkit.WebView import android.webkit.WebViewClient import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView import com.example.neveropen.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private var binding: ActivityMainBinding? = null private var createMenu: Menu? = null @SuppressLint ( "SetJavaScriptEnabled" ) override fun onCreate(savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding!!.getRoot()) // this will enable the javascript in the WebView binding!!.webView.getSettings().setJavaScriptEnabled( true ) // load https://www.geeksforgeeks.org url in the WebView. // WebViewClient allows you to handle // onPageFinished and override Url loading. binding!!.webView.setWebViewClient(object : WebViewClient() { override fun onPageStarted(view: WebView, url: String, favicon: Bitmap) { super .onPageStarted(view, url, favicon) // set the visibility to visible when // the page starts loading binding!!.progressBar.setVisibility(View.VISIBLE) } override fun onPageFinished(view: WebView, url: String) { super .onPageFinished(view, url) // set the visibility to gone when // the page gets loaded completely binding!!.progressBar.setVisibility(View.GONE) } }) } override fun onCreateOptionsMenu(menu: Menu): Boolean { super .onCreateOptionsMenu(menu) // create an reference of menu createMenu = menu val inflater = menuInflater inflater.inflate(R.menu.menu, menu) return true } @SuppressLint ( "NonConstantResourceId" ) override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.itemSearch -> { // create a searchView inside the actionbar // when search menu item is clicked val searchView = item.actionView as SearchView // set the width to maximum searchView.maxWidth = Int.MAX_VALUE searchView.queryHint = "Search any keyword.." // set a listener when the start typing in the SearchView searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { // clear the focus when // the text is submitted searchView.clearFocus() return false } override fun onQueryTextChange(query: String): Boolean { // When the query length is greater // than 0 we will perform the search if (query.length > 0 ) { // findAllAsync finds all instances // on the page and // highlights them,asynchronously. binding!!.webView.findAllAsync(query) // set the visibility of nextItem // and previous item to true createMenu!!.getItem( 1 ).isVisible = true createMenu!!.getItem( 2 ).isVisible = true } else { binding!!.webView.clearMatches() // set the visibility of nextItem // and previous item to false // when query length is 0 createMenu!!.getItem( 1 ).isVisible = false createMenu!!.getItem( 2 ).isVisible = false } return true } }) } R.id.itemNext -> // findNext highlights and scrolls to the next match // found by findAllAsync(String), // wrapping around page boundaries as necessary. // true scrolls to the next match binding!!.webView.findNext( true ) R.id.itemPrevious -> // findNext highlights and scrolls to the next match found // by findAllAsync(String), // wrapping around page boundaries as necessary. // false scrolls to the previous match binding!!.webView.findNext( false ) } return super .onOptionsItemSelected(item) } } |
Java
import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SearchView; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import com.example.neveropen.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; private Menu createMenu; @SuppressLint ( "SetJavaScriptEnabled" ) @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // this will enable the javascript in the WebView binding.webView.getSettings().setJavaScriptEnabled( true ); // load https://www.geeksforgeeks.org url in the WebView. // WebViewClient allows you to handle // onPageFinished and override Url loading. binding.webView.setWebViewClient( new WebViewClient(){ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super .onPageStarted(view, url, favicon); // set the visibility to visible when // the page starts loading binding.progressBar.setVisibility(View.VISIBLE); } @Override public void onPageFinished(WebView view, String url) { super .onPageFinished(view, url); // set the visibility to gone when the page // gets loaded completely binding.progressBar.setVisibility(View.GONE); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { super .onCreateOptionsMenu(menu); // create an reference of menu createMenu = menu; MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true ; } @SuppressLint ( "NonConstantResourceId" ) @Override public boolean onOptionsItemSelected( @NonNull MenuItem item) { switch (item.getItemId()){ case R.id.itemSearch: // create a searchView inside the actionbar // when search menu item is clicked SearchView searchView = (SearchView) item.getActionView(); // set the width to maximum searchView.setMaxWidth(Integer.MAX_VALUE); searchView.setQueryHint( "Search any keyword.." ); // set a listener when the start typing in the SearchView searchView.setOnQueryTextListener( new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // clear the focus when // the text is submitted searchView.clearFocus(); return false ; } @Override public boolean onQueryTextChange(String query) { // When the query length is greater // than 0 we will perform the search if (query.length()> 0 ){ // findAllAsync finds all instances // on the page and // highlights them,asynchronously. binding.webView.findAllAsync(query); // set the visibility of nextItem // and previous item to true createMenu.getItem( 1 ).setVisible( true ); createMenu.getItem( 2 ).setVisible( true ); } else { binding.webView.clearMatches(); // set the visibility of nextItem // and previous item to false // when query length is 0 createMenu.getItem( 1 ).setVisible( false ); createMenu.getItem( 2 ).setVisible( false ); } return true ; } }); break ; case R.id.itemNext: // findNext highlights and scrolls to the next match // found by findAllAsync(String), // wrapping around page boundaries as necessary. // true scrolls to the next match binding.webView.findNext( true ); break ; case R.id.itemPrevious: // findNext highlights and scrolls to the next match // found by findAllAsync(String), // wrapping around page boundaries as necessary. // false scrolls to the previous match binding.webView.findNext( false ); } return super .onOptionsItemSelected(item); } } |
Output: